linux系統編程之訊號(四)

來源:互聯網
上載者:User

標籤:style   class   blog   c   code   java   

今天繼續探討訊號相關的東東,話不多說,正入正題:

訊號在核心中的表示:下面用圖來進一步描述這種訊號從產生到遞達之間的狀態( 訊號阻塞與未訣): 那是怎麼來決定的呢?下面慢慢來舉例分解:所以,通過這些圖,可以描述訊號從產生到遞達的一個過程,上面的理解起來可能有點難,下面會用代碼來進一步闡述,在進行實驗之前,還需瞭解一些函數的使用,這些函數在實驗中都會被用到,也就是訊號集操作函數。 訊號集操作函數:其中解釋一下sigset_t,百度百科解釋為:而這個函數的意義就是將這64位清0這個函數的意義是將這屏蔽字的64位都變為1將這個訊號所對應的位置為1將這個訊號所對應的位置為0檢測這一個訊號所對應的位當前是0還是1 以上是操作訊號集的五個相關的函數,但是注意: 這五個函數僅僅是改變這個訊號集變數,如set,並非真正改變進程訊號當中的屏蔽字,所以接下來介紹的函數就是改變訊號當中的屏蔽字的 sigprocmask:好了,理論說了很多,下面正式開始實驗,來體會一下一個訊號從產生到遞達的一個狀態轉換過程:首先,我們列印出系統的未訣訊號,目的是為了觀察之後的狀態:
#include <unistd.h>#include <sys/stat.h>#include <sys/wait.h>#include <sys/types.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <signal.h>#define ERR_EXIT(m)     do     {         perror(m);         exit(EXIT_FAILURE);     } while(0)void handler(int sig);void printsigset(sigset_t *set)//列印出訊號集的狀態,其中參數set為未訣狀態的訊號集{    int i;    for (i=1; i<NSIG; ++i)//NSIG表示訊號的最大值,也就是等於64    {        if (sigismember(set, i))//說明是未訣狀態的訊號            putchar(‘1‘);        else            putchar(‘0‘);//說明不是未訣狀態的訊號    }    printf("\n");}int main(int argc, char *argv[]){    sigset_t pset;    for (;;)    {        sigpending(&pset);//該函數是擷取進程當中未訣狀態的訊號集 ,儲存在pset當中        printsigset(&pset);//列印訊號集的狀態,看有沒有未訣狀態的訊號產生        sleep(1);    }    return 0;}

【說明】:sigpending是用來擷取進程中所有的未訣訊號集:

這時看一下運行效果:

可以發現,目前狀態沒有未訣的訊號,因為還沒有被阻塞的訊號過,訊號也沒有產生過,所以不可能有未訣的狀態。
這時,我們來安裝一個SIGINT訊號:

#include <unistd.h>#include <sys/stat.h>#include <sys/wait.h>#include <sys/types.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <signal.h>#define ERR_EXIT(m)     do     {         perror(m);         exit(EXIT_FAILURE);     } while(0)void handler(int sig);void printsigset(sigset_t *set){    int i;    for (i=1; i<NSIG; ++i)    {        if (sigismember(set, i))            putchar(‘1‘);        else            putchar(‘0‘);    }    printf("\n");}int main(int argc, char *argv[]){    sigset_t pset;    if (signal(SIGINT, handler) == SIG_ERR)//安裝一個SIGINT訊號        ERR_EXIT("signal error");    for (;;)    {        sigpending(&pset);        printsigset(&pset);        sleep(1);    }    return 0;}void handler(int sig){        printf("recv a sig=%d\n", sig);}

這時再看下效果:

從結果來看,訊號被直接遞達了,所以這次也沒有看到有1的未訣狀態的訊號,因為訊號必須被阻塞才會出現未訣狀態,所以接下來將SIGINT訊號利用上面介紹到的函數來將其阻塞掉:

#include <unistd.h>#include <sys/stat.h>#include <sys/wait.h>#include <sys/types.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <signal.h>#define ERR_EXIT(m)     do     {         perror(m);         exit(EXIT_FAILURE);     } while(0)void handler(int sig);void printsigset(sigset_t *set){    int i;    for (i=1; i<NSIG; ++i)    {        if (sigismember(set, i))            putchar(‘1‘);        else            putchar(‘0‘);    }    printf("\n");}int main(int argc, char *argv[]){    sigset_t pset;        sigset_t bset;    sigemptyset(&bset);//將訊號集清0    sigaddset(&bset, SIGINT);//將SIGINT所對應的位置1    if (signal(SIGINT, handler) == SIG_ERR)        ERR_EXIT("signal error");    sigprocmask(SIG_BLOCK, &bset, NULL);//更改進程中的訊號屏蔽字,其中第三個參數傳NULL,因為不關心它原來的訊號屏蔽字    for (;;)    {        sigpending(&pset);        printsigset(&pset);        sleep(1);    }    return 0;}void handler(int sig){        printf("recv a sig=%d\n", sig);}

編譯運行:

從結果來看,將SIGINT訊號來了,由於添加到了訊號屏蔽字為1,所以會被阻塞掉,並且可以看到SIGINT對應的位也列印為1了。

【說明】:SIGINT對應的位是指:

下面,我們做一件事情,就是當我們按下ctrl+\解除阻塞,這樣處於未訣狀態的訊號就會被遞達,則對應的未訣狀態位也會還原成0,具體代碼如下:

#include <unistd.h>#include <sys/stat.h>#include <sys/wait.h>#include <sys/types.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <signal.h>#define ERR_EXIT(m)     do     {         perror(m);         exit(EXIT_FAILURE);     } while(0)void handler(int sig);void printsigset(sigset_t *set){    int i;    for (i=1; i<NSIG; ++i)    {        if (sigismember(set, i))            putchar(‘1‘);        else            putchar(‘0‘);    }    printf("\n");}int main(int argc, char *argv[]){    sigset_t pset;    sigset_t bset;    sigemptyset(&bset);    sigaddset(&bset, SIGINT);    if (signal(SIGINT, handler) == SIG_ERR)        ERR_EXIT("signal error");    if (signal(SIGQUIT, handler) == SIG_ERR)//註冊一個ctrl+c訊號        ERR_EXIT("signal error");    sigprocmask(SIG_BLOCK, &bset, NULL);    for (;;)    {        sigpending(&pset);        printsigset(&pset);        sleep(1);    }    return 0;}void handler(int sig){    if (sig == SIGINT)        printf("recv a sig=%d\n", sig);    else if (sig == SIGQUIT)    {        sigset_t uset;//當按下ctrl+\時,則對SIGINT訊號解除阻塞        sigemptyset(&uset);        sigaddset(&uset, SIGINT);        sigprocmask(SIG_UNBLOCK, &uset, NULL);    }}

編譯運行:

從中可以看到,當我們按下ctrl+\時,並沒有退出,而是解除了阻塞,所以對應的SIGINT位也變為0了。

另外,看下這種情況:

多次按了ctrl+c,可在按ctrl+\解除阻塞時,只響應了一次訊號處理函數,這也由於SIGINT是不可靠訊號,不支援排隊。

另外,由於我們捕獲了ctrl+\訊號,所以沒辦法退出這個進程了,那怎麼辦呢,可以利用shell命令將其強制殺掉如下:

好了,今天學的東西可能有些生澀,需好好消化,下節再見!

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.