Linux系统编程(五)时序竞态
時(shí)序競(jìng)態(tài)
- 產(chǎn)生原因
- 改進(jìn)
- 總結(jié)
產(chǎn)生原因
#include <cstdio> #include <stdio.h> #include <sys/time.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <errno.h>void catch_sigalrm(int signo) {printf("pause sucess 11111\n"); }unsigned int mysleep(unsigned int seconds) {struct sigaction act, oldact;sigset_t new1,old;act.sa_flags = 0;act.sa_handler = catch_sigalrm;sigemptyset(&act.sa_mask);int ret=sigaction(SIGALRM, &act, &oldact);if (ret == -1){perror("sigaction error:");exit(1);}sigemptyset(&new1);sigemptyset(&old);sigaddset(&new1,SIGALRM);sigaddset(&old, SIGALRM);sigprocmask(SIG_BLOCK,&new1, NULL);sigprocmask(SIG_UNBLOCK, &old, NULL);alarm(seconds);ret=pause();//主動(dòng)掛起 等信號(hào)if (ret == -1 && errno== EINTR){printf("pause sucess \n");}ret=alarm(0);sigaction(SIGALRM,&oldact,NULL);return ret; }int main() {mysleep(3);printf("----------------\n");return 0; }如果進(jìn)程在執(zhí)行完alarm函數(shù)后,突然失去CPU,被阻塞等待(這是有可能的,進(jìn)程在執(zhí)行過程中,若非原子操作,都有可能隨時(shí)失去CPU),如果失去CPU的時(shí)間大于了執(zhí)行完,則此時(shí)在執(zhí)行pause函數(shù)前,信號(hào)已經(jīng)到了,因此會(huì)先處理信號(hào)(軟中斷,而不是先執(zhí)行pause函數(shù)),在信號(hào)處理完后,再去執(zhí)行pause函數(shù),此時(shí)進(jìn)程會(huì)被永遠(yuǎn)掛起,不會(huì)被喚醒,因?yàn)镾IGALRM信號(hào)已經(jīng)被處理了。
時(shí)序競(jìng)態(tài):即由于進(jìn)程之間執(zhí)行的順序不同,導(dǎo)致同一個(gè)進(jìn)程多次運(yùn)行后產(chǎn)生了不同結(jié)果的現(xiàn)象。如上述sleep函數(shù),有時(shí)執(zhí)行結(jié)果是正確的,有時(shí)卻會(huì)導(dǎo)致進(jìn)程永遠(yuǎn)被掛起,因此這就是一個(gè)時(shí)序競(jìng)態(tài)問題。因此需要重新對(duì)該函數(shù)進(jìn)行改進(jìn)。
改進(jìn)
代碼如下(示例):
#include <cstdio> #include <stdio.h> #include <sys/time.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <errno.h>void doaction(int signo) {printf("---------%d 信號(hào)-------\n",signo); }int mysleep(int second) {int unslept;struct sigaction cur, old;sigset_t n_ew,o_ld,supemask;//安裝信號(hào)cur.sa_flags = 0;sigemptyset(&cur.sa_mask);cur.sa_handler = doaction;sigaction(SIGALRM,&cur, &old);//設(shè)置阻塞信號(hào)集,阻塞SIGALRM信號(hào)sigemptyset(&n_ew);sigaddset(&n_ew,SIGALRM);sigprocmask(SIG_BLOCK,&n_ew, &o_ld);//定時(shí)alarm(second);//構(gòu)建一個(gè)臨時(shí)的sigsuspend有效阻塞信號(hào)集supemask = o_ld;sigemptyset(&supemask);sigsuspend(&supemask);//supemask未阻塞信號(hào)掛起unslept = alarm(0);//恢復(fù)之前狀態(tài)sigaction(SIGALRM,&old,NULL);sigprocmask(SIG_SETMASK,&o_ld,NULL);return unslept;//int ret=pause();//if (ret == -1 && errno == EINTR)//{// printf("pause success\n");//}}int main() {mysleep(3);}使用sigsuspend函數(shù),sigsuspend具有“原子操作“,這樣就能夠避免。
總結(jié)
- 競(jìng)態(tài)條件,跟系統(tǒng)負(fù)載有很緊密的關(guān)系,體現(xiàn)出信號(hào)的不可靠性。系統(tǒng)負(fù)載越嚴(yán)重,信號(hào)不可靠性越強(qiáng)。
- 不可靠由其實(shí)現(xiàn)原理所致。信號(hào)是通過軟件方式實(shí)現(xiàn)(跟內(nèi)核調(diào)度高度依賴,延時(shí)性強(qiáng)),每次系統(tǒng)調(diào)用結(jié)束后,或中斷處理處理結(jié)束后,需通過掃描PCB中的未決信號(hào)集,來判斷是否應(yīng)處理某個(gè)信號(hào)。當(dāng)系統(tǒng)負(fù)載過重時(shí),會(huì)出現(xiàn)時(shí)序混亂。
- 這種意外情況只能在編寫程序過程中,提早預(yù)見,主動(dòng)規(guī)避,而無法通過gdb程序調(diào)試等其他手段彌補(bǔ)。且由于該錯(cuò)誤不具規(guī)律性,后期捕捉和重現(xiàn)十分困難。
總結(jié)
以上是生活随笔為你收集整理的Linux系统编程(五)时序竞态的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CSS遇到一个小问题?关于不同浏览器的兼
- 下一篇: Linux系统编程(六)守护进程