91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

volatile關鍵字,竟態條件

發布時間:2020-07-16 14:47:50 來源:網絡 閱讀:475 作者:小止1995 欄目:編程語言

volatile:防止編譯器性能優化,與移植性有關。

#include<stdio.h>
#include<signal.h>
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循環中:沒有寫入修改done的值,編譯器會在讀取變量的時候,將其從內存拿出存入寄存器并比較,在下次讀取時,直接從寄存器中取該變量的值。 

而在信號處理函數中,有修改done的值,需寫回內存。

可指定編譯器優化級別

編譯器優化級別:

  1. gcc -o my_volatile  my_volatile.c -O0//不優化

  2. gcc -o my_volatile  my_volatile.c -O1//默認

  3. gcc -o my_volatile  my_volatile.c -O2

  4. gcc -o my_volatile  my_volatile.c -O3//優化級別最高

此時會發生內存級別的不一致:寄存器:0,內存:1.

運行結果:

volatile關鍵字,竟態條件

要改變此程序顯示預期效果,只需定義done為:volatile int done=0;//這樣每次使用done時都會從內存中取done的值。

sig_atomic_t:由C語言提供。

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

為了解決這些平臺相關的問,C標準定義了一個類型sig_atomic_t,在不同平臺的C語言庫中取不同的類型,例如在32位機 上定義sig_atomic_tint類型。

竟態條件:

由于異步事件在任何時候都有可能發生(這里的異步事件指出現更優 先級的進程),如果我們寫程序時考慮不周密,就可能由于時序問題而導致錯誤,這叫做競態條件 (Race Condition)

#include<stdio.h>
#include<signal.h>
#include<string.h>
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);//注冊信號處理函數
    alarm(time);//time秒后讓系統發SIGALRM信號
    pause();//內核切換到別的進程運行
    int ret=alarm(0);
    sigaction(SIGALRM,&old,NULL);//恢復默認信號處理動作
    return ret;
}
int main()
{
    while(1)
    {
        printf("I am sleep...\n");
        my_sleep(5);
    }
    return 0;
}


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

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

要是解除信號屏蔽掛起等待信號這兩步能合并成一個原子操作就好了,這正是sigsuspend
函數的功 能。 sigsuspend包含了pause的掛起等待功能,同時解決了競態條件的問題,在對
時序要求嚴格的場合下都應該調用sigsuspend不是pause

注:調用sigsuspend,進程的信號屏蔽字由sigmask參數指定,可以通過指定sigmask來臨時
解除對某 個信號的屏蔽,然后掛起等待,sigsuspend返回時,進程的信號屏蔽字恢復為原
來的值,如果原來對該信號是屏蔽的,sigsuspend返回后仍然是屏蔽的。

#include<stdio.h>
#include<signal.h>
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);//注冊SIGALRM的信號處理函數
    sigemptyset(&newmask);
    sigaddset(&newmask,SIGALRM);
    sigprocmask(SIG_BLOCK,&newmask,&oldmask);//屏蔽SIGALRM信號;
    alarm(time);
    suspmask=oldmask;
    sigdelset(&suspmask,SIGALRM);//解除suspmask中SIGALRM信號的屏蔽;
    sigsuspend(&suspmask);//用suspmask去替換PCB中的block表,從而解除對SIGALRM信號的阻塞
    int ret=alarm(0);
    sigaction(SIGALRM,&oldact,NULL);
    sigprocmask(SIG_SETMASK,&oldmask,NULL);//恢復之前的系統默認處理信號方式
    return ret;
}
int main()
{
    while(1)
    {
        printf("I am sleep\n");
        sleep(5);
    }
    return 0;
}

進程在終止時會給父進程發SIGCHLD信號,該信號的默認處理動作是忽略,父進程可以自定義SIGCHLD信號的處理函數,這樣父進程只需專心處理自己的工作,不必關心子子進程了,子進程終止時會通知父進程,父進程在信號處理函數中調用wait清理子進程即可。

優點:沒花費時間在等待上,直到收到信號(異步信號)

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
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);//保證父進程已注冊完信號處理函數,父,子進程誰先運行不確定
         printf("child is quit!\n");
         exit(1);
    }
    else
    {
         signal(SIGCHLD,my_sigchld);
         while(1);
    }
    return 0;
}

但是,如果一個父進程有100個子進程,收到好多SIGCHLD信號,只會保存一份,只能wait一份,故應該修改代碼防止此情況發生

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);
    }
 }


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

长海县| 固原市| 宿州市| 清苑县| 文成县| 石泉县| 崇文区| 黄龙县| 益阳市| 安乡县| 体育| 大足县| 兴和县| 梅州市| 喀喇沁旗| 凤山县| 中卫市| 永吉县| 邵阳县| 宝兴县| 山阳县| 瓮安县| 临夏市| 三台县| 醴陵市| 莆田市| 神池县| 齐齐哈尔市| 繁昌县| 岱山县| 新巴尔虎右旗| 屯昌县| 大余县| 梨树县| 静宁县| 扶绥县| 合肥市| 池州市| 平定县| 化州市| 潼南县|