真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

volatile關(guān)鍵字,竟態(tài)條件

volatile:防止編譯器性能優(yōu)化,與移植性有關(guān)。

在柘榮等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站建設(shè)、成都做網(wǎng)站 網(wǎng)站設(shè)計(jì)制作按需求定制網(wǎng)站,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),成都營(yíng)銷網(wǎng)站建設(shè),成都外貿(mào)網(wǎng)站建設(shè),柘榮網(wǎng)站建設(shè)費(fèi)用合理。

#include
#include
int done=0;
void handle(int sig)
{
    printf("get sig %d\n",sig);
    done=1;
}
int main()
{
    signal(SIGINT,handle);
    while(!done);
}

Makefile:

my_volatile:my_volatile.c

     gcc -o $@ $^  -O3

.PHONY:clean

clean:

     rm -f my_volatile

在while循環(huán)中:沒有寫入修改done的值,編譯器會(huì)在讀取變量的時(shí)候,將其從內(nèi)存拿出存入寄存器并比較,在下次讀取時(shí),直接從寄存器中取該變量的值。 

而在信號(hào)處理函數(shù)中,有修改done的值,需寫回內(nèi)存。

可指定編譯器優(yōu)化級(jí)別

編譯器優(yōu)化級(jí)別:

  1. gcc -o my_volatile  my_volatile.c -O0//不優(yōu)化

  2. gcc -o my_volatile  my_volatile.c -O1//默認(rèn)

  3. gcc -o my_volatile  my_volatile.c -O2

  4. gcc -o my_volatile  my_volatile.c -O3//優(yōu)化級(jí)別最高

此時(shí)會(huì)發(fā)生內(nèi)存級(jí)別的不一致:寄存器:0,內(nèi)存:1.

運(yùn)行結(jié)果:

volatile關(guān)鍵字,竟態(tài)條件

要改變此程序顯示預(yù)期效果,只需定義done為:volatile int done=0;//這樣每次使用done時(shí)都會(huì)從內(nèi)存中取done的值。

sig_atomic_t:由C語言提供。

雖然C代碼只有一行,但是在32位機(jī)上對(duì)一個(gè)64位的long long變量賦值需要兩條指令完成,因此不是原子操作。同樣地,讀取這個(gè)變量到寄存器需要兩個(gè)32位寄存器才放得下,也需要兩條指令, 不是原子操作。

為了解決這些平臺(tái)相關(guān)的問題,C標(biāo)準(zhǔn)定義了一個(gè)類型sig_atomic_t,在不同平臺(tái)的C語言庫(kù)中取不同的類型,例如在32位機(jī) 上定義sig_atomic_t為int類型。

竟態(tài)條件:

由于異步事件在任何時(shí)候都有可能發(fā)生(這里的異步事件指出現(xiàn)更優(yōu) 先級(jí)的進(jìn)程),如果我們寫程序時(shí)考慮不周密,就可能由于時(shí)序問題而導(dǎo)致錯(cuò)誤,這叫做競(jìng)態(tài)條件 (Race Condition)。

#include
#include
#include
void handler(int sig)
{
    //do nothing
}
int my_sleep(int time)
{
    struct sigaction act;
    act.sa_handler=handler;
    act.sa_flags=0;
    sigemptyset(&act.sa_mask);
    struct sigaction old;
    memset(&old,'\0',sizeof(old));
    sigaction(SIGALRM,&act,&old);//注冊(cè)信號(hào)處理函數(shù)
    alarm(time);//time秒后讓系統(tǒng)發(fā)SIGALRM信號(hào)
    pause();//內(nèi)核切換到別的進(jìn)程運(yùn)行
    int ret=alarm(0);
    sigaction(SIGALRM,&old,NULL);//恢復(fù)默認(rèn)信號(hào)處理動(dòng)作
    return ret;
}
int main()
{
    while(1)
    {
        printf("I am sleep...\n");
        my_sleep(5);
    }
    return 0;
}

雖然alarm(nsecs)緊接著的下一行就是pause(),但是無法保證pause()一定會(huì)在調(diào)用alarm(nsecs)之 后的nsecs秒之內(nèi)被調(diào)用。

在調(diào)用pause之前屏蔽SIGALRM信號(hào)使它不能提前遞達(dá)就可以了。
1. 屏蔽SIGALRM信號(hào);
2. alarm(nsecs);
3. 解除對(duì)SIGALRM信號(hào)的屏蔽;
4. pause();
從解除信號(hào)屏蔽到調(diào)用pause之間存在間隙,SIGALRM仍有可能在這個(gè)間隙遞達(dá)。

要是“解除信號(hào)屏蔽”和“掛起等待信號(hào)”這兩步能合并成一個(gè)原子操作就好了,這正是sigsuspend
函數(shù)的功 能。 sigsuspend包含了pause的掛起等待功能,同時(shí)解決了競(jìng)態(tài)條件的問題,在對(duì)
時(shí)序要求嚴(yán)格的場(chǎng)合下都應(yīng)該調(diào)用sigsuspend不是pause。

注:調(diào)用sigsuspend時(shí),進(jìn)程的信號(hào)屏蔽字由sigmask參數(shù)指定,可以通過指定sigmask來臨時(shí)
解除對(duì)某 個(gè)信號(hào)的屏蔽,然后掛起等待,當(dāng)sigsuspend返回時(shí),進(jìn)程的信號(hào)屏蔽字恢復(fù)為原
來的值,如果原來對(duì)該信號(hào)是屏蔽的,從sigsuspend返回后仍然是屏蔽的。

#include
#include
void handle(int sig)
{
    //do nothing
}
int sleep(int time)
{
    struct sigaction oldact,newact;
    sigset_t newmask,oldmask,suspmask;
    newact.sa_handler=handle;
    newact.sa_flags=0;
    sigemptyset(&newact.sa_mask);
    sigaction(SIGALRM,&newact,&oldact);//注冊(cè)SIGALRM的信號(hào)處理函數(shù)
    sigemptyset(&newmask);
    sigaddset(&newmask,SIGALRM);
    sigprocmask(SIG_BLOCK,&newmask,&oldmask);//屏蔽SIGALRM信號(hào);
    alarm(time);
    suspmask=oldmask;
    sigdelset(&suspmask,SIGALRM);//解除suspmask中SIGALRM信號(hào)的屏蔽;
    sigsuspend(&suspmask);//用suspmask去替換PCB中的block表,從而解除對(duì)SIGALRM信號(hào)的阻塞
    int ret=alarm(0);
    sigaction(SIGALRM,&oldact,NULL);
    sigprocmask(SIG_SETMASK,&oldmask,NULL);//恢復(fù)之前的系統(tǒng)默認(rèn)處理信號(hào)方式
    return ret;
}
int main()
{
    while(1)
    {
        printf("I am sleep\n");
        sleep(5);
    }
    return 0;
}

子進(jìn)程在終止時(shí)會(huì)給父進(jìn)程發(fā)SIGCHLD信號(hào),該信號(hào)的默認(rèn)處理動(dòng)作是忽略,父進(jìn)程可以自定義SIGCHLD信號(hào)的處理函數(shù),這樣父進(jìn)程只需專心處理自己的工作,不必關(guān)心子子進(jìn)程了,子進(jìn)程終止時(shí)會(huì)通知父進(jìn)程,父進(jìn)程在信號(hào)處理函數(shù)中調(diào)用wait清理子進(jìn)程即可。

優(yōu)點(diǎn):沒花費(fèi)時(shí)間在等待上,直到收到信號(hào)(異步信號(hào))

#include
#include
#include
#include
void my_sigchld(int sig)
{
    int status=0;
    pid_t ret=waitpid(-1,&status,0);
    if(ret>0)
    {
        printf("sig: %d,code: %d\n",status&0xff,(status>>8)&0xff);
    }
}
int main()
{
    pid_t tid=fork();
    if(tid<0)
    {
        perror("fork");
        exit(1);
    }
    else if(tid==0)
    {
         sleep(10);//保證父進(jìn)程已注冊(cè)完信號(hào)處理函數(shù),父,子進(jìn)程誰先運(yùn)行不確定
         printf("child is quit!\n");
         exit(1);
    }
    else
    {
         signal(SIGCHLD,my_sigchld);
         while(1);
    }
    return 0;
}

但是,如果一個(gè)父進(jìn)程有100個(gè)子進(jìn)程,收到好多SIGCHLD信號(hào),只會(huì)保存一份,只能wait一份,故應(yīng)該修改代碼防止此情況發(fā)生

void my_sigchld(int sig)
{
    int status=0;
    pid_t ret;
    while((ret=waitpid(-1,&status,0))>0)
    {
        printf("sig: %d,code: %d\n",status&0xff,(status>>8)&0xff);
    }
 }

本文名稱:volatile關(guān)鍵字,竟態(tài)條件
標(biāo)題來源:http://weahome.cn/article/gppeds.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部