天天看點

2信号處理之:信号産生原因,程序處理信号行為,信号集處理函數,PCB的信号集,sigprocmask()和sigpending(),信号捕捉設定,sigaction,C标準庫信号處理函數,可重入函數,



1信号産生原因

2信号處理之:信号産生原因,程式處理信号行為,信号集處理函數,PCB的信号集,sigprocmask()和sigpending(),信号捕捉設定,sigaction,C标準庫信号處理函數,可重入函數,
2信号處理之:信号産生原因,程式處理信号行為,信号集處理函數,PCB的信号集,sigprocmask()和sigpending(),信号捕捉設定,sigaction,C标準庫信号處理函數,可重入函數,

2.程序處理信号行為

manpage裡信号3中處理方式:

sig_ign

sig_dfl                                           

預設term動作

a signal handling function

程序處理信号

a預設處理動作

term  

中斷

core   

core(調試的時候産生)

gcc –g file.c

 ulimit –c 1024

 gdb a.out core

ign     

忽略

stop    

停止

cont    

繼續

b忽略

c捕捉(使用者自定義處理函數)

3信号集處理函數

sigset_t為信号集,可sizeof(sigset_t)檢視

将信号集裡面的每位都置0

int sigemptyset(sigset_t *set)

将所有信号集都置1

int sigfillset(sigset_t *set)

添加一個信号,也就是将block阻塞信号集裡面的某一位置成1

int sigaddset(sigset_t *set, int signo)

将信号集中某一位取消置1

int sigdelset(sigset_t *set, int signo)

測試某個信号集中的信号是否為1

int sigismember(const sigset_t *set, intsigno)

4 pcb的信号集

2信号處理之:信号産生原因,程式處理信号行為,信号集處理函數,PCB的信号集,sigprocmask()和sigpending(),信号捕捉設定,sigaction,C标準庫信号處理函數,可重入函數,

信号在核心中的表示示意圖

如果在程序解除對某信号的阻塞之前這種信号産生過多次,将如何處理?posix.1允

許系統遞送該信号一次或多次。linux是這樣實作的:正常信号在遞達之前産生多次隻

計一次,而實時信号在遞達之前産生多次可以依次放在一個隊列裡。本章不讨論實時信

号。從上圖來看,每個信号隻有一個bit的未決标志,非0即1,不記錄該信号産生了多少

次,阻塞标志也是這樣表示的。是以,未決和阻塞标志可以用相同的資料類型sigset_t

來存儲,sigset_t稱為信号集,這個類型可以表示每個信号的“有效”或“無效”狀态,

在阻塞信号集中“有效”和“無效”的含義是該信号是否被阻塞,而在未決信号集中“有

效”和“無效”的含義是該信号是否處于未決狀态。

阻塞信号集也叫做目前程序的信号屏蔽字(signal mask),這裡的“屏蔽”應該了解

為阻塞而不是忽略。

5sigprocmask

調用函數sigprocmask可以讀取或更改程序的信号屏蔽字。

依賴的頭檔案:

#include <signal.h>

函數聲明:

*set是傳入的信号,*oset表示原來的信号集是什麼,相當于是*set的一個備份

intsigprocmask(int how, const sigset_t *set, sigset_t *oset);         

傳回值:若成功則為0,若出錯則為-1

如果oset是非空指針,則讀取程序的目前信号屏蔽字通過oset參數傳出。如果set是非空指針,則更改程序的信号屏蔽字,參數how訓示如何更改。如果oset和set都是非空指針,則先将原來的信号屏蔽字備份到oset裡,然後根據set和how參數更改信号屏蔽字。假設目前的信号屏蔽字為mask,下表說明了how參數的可選值。

how參數的含義

sig_block set包含了我們希望添加到目前信号屏蔽字的信号,相當于mask=mask|set

sig_unblock set包含了我們希望從目前信号屏蔽字中解除阻塞的信号,相當于mask=mask&~set

sig_setmask

設定目前信号屏蔽字為set所指向的值,相當于mask=set

6sigpending(未決列印信号)

#include<signal.h>

int sigpending(sigset_t *set)

sigpending讀取目前程序的未決信号集,通過set參數傳出。調用成功則傳回0,出錯則

傳回-1。

6案例說明:

2信号處理之:信号産生原因,程式處理信号行為,信号集處理函數,PCB的信号集,sigprocmask()和sigpending(),信号捕捉設定,sigaction,C标準庫信号處理函數,可重入函數,

運作結果:

程式運作時,每秒鐘把各信号的未決狀态列印一遍,由于我們阻塞了sigint信号,按ctrl-c将會使sigint信号處于未決狀态,按ctrl-\仍然可以終止程式,因為sigquit信号沒有阻塞。

2信号處理之:信号産生原因,程式處理信号行為,信号集處理函數,PCB的信号集,sigprocmask()和sigpending(),信号捕捉設定,sigaction,C标準庫信号處理函數,可重入函數,

這時按ctrl+\結束。

7信号捕捉設定

2信号處理之:信号産生原因,程式處理信号行為,信号集處理函數,PCB的信号集,sigprocmask()和sigpending(),信号捕捉設定,sigaction,C标準庫信号處理函數,可重入函數,

8.sigaction

int sigaction(int signum, const structsigaction *act,

struct sigaction *oldact);

struct sigaction

定義:

struct sigaction {

void (*sa_handler)(int);

void (*sa_sigaction)(int, siginfo_t *, void *);

sigset_t sa_mask;

int sa_flags;

void (*sa_restorer)(void);

};

sa_handler:早期的捕捉函數

sa_sigaction :

新添加的捕捉函數,可以傳參,和sa_handler互斥,兩者通過sa_flags選擇采用哪種捕捉函數

sa_mask :

在執行捕捉函數時,設定阻塞其它信号,sa_mask|

程序阻塞信号集,退出捕捉函數後,還原回原有的阻塞信号集

sa_flags : sa_siginfo

或者0

sa_restorer:保留,已過時。

案例說明:

#include<stdio.h>

#include<unistd.h>

void do_sig(int num)

{

    int n = 5;

    printf("i am do_sig\n");

    printf("num = %d\n",num);

    while(n--)

    {

      printf("num = %d\n",num);

        sleep(1);

    }

}

int main(void)

    struct sigaction act;

    act.sa_handler = do_sig;

    //act.sa_handler = sig_dfl;

    //act.sa_handler = sig_ign;

    sigemptyset(&act.sa_mask);

    sigaddset(&act.sa_mask,sigquit);

    act.sa_flags = 0;

    sigaction(sigint,&act,null);

 while(1)

        printf("**********\n");

sleep(1);

    return 0;

9 c标準庫信号處理函數

typedef void (*sighandler_t)(int)

sighandler_t signal(int signum,sighandler_t handler)

int system(const char *command)

system的本質是:集合fork,exec,wait一體

10

可重入函數

a:不含全局變量和靜态變量是可重入函數的一個要素

b:可重入函數man 

7  signal

c:在信号捕捉函數裡應可重入函數

例如:strtok就是一個不可重入函數,因為strtok内部維護了一個内部靜态指針,儲存上一次切割到的位置,如果信号的捕捉函數中也去調用strtok函數,則會造成切割字元串混亂,應用strtok_r版本,r表示可重入。

11時序競态

int pause(void)

使調用程序挂起,直到有信号遞達,如果遞達信号是忽略,則繼續挂起

int sigsuspend(const sigset_t *mask)

以通過指定mask來臨時解除對某個信号的屏蔽,然後挂起等待,當sigsuspend傳回時,程序的信号屏蔽字恢複為原來的值

#include <unistd.h>

#include <stdio.h>

void sig_alrm(int signo)

/* nothing to do */

unsigned int mysleep(unsigned int nsecs)

struct sigaction newact, oldact;

unsigned int unslept;

newact.sa_handler = sig_alrm;

sigemptyset(&newact.sa_mask);

newact.sa_flags = 0;

sigaction(sigalrm, &newact, &oldact);

alarm(nsecs);

//在alarm的時候,可能會轉到其它程式,這之後永遠都執行不到下面的這行,因為信号已經執行過了

pause();

unslept = alarm(0);

sigaction(sigalrm, &oldact, null);

return unslept;

while(1){

mysleep(2);

printf("two seconds passed\n");

return 0;

mysleep的改進版

{  

    /* nothing to do*/

unsigned int mysleep(unsigned int nsecs) {  

struct sigaction newact,oldact;

sigset_tnewmask,oldmask,suspmask;

/*set our handler,saveprevious information*/

newact.sa_handler =sig_alrm;

  sigemptyset(&newact.sa_mask);

   sigaction(sigalrm,&newact,&oldact);

/*block sigalrm and savecurrent signal mask*/

sigemptyset(&newmask);

 sigaddset(&newmask,sigalrm);

 sigprocmask(sig_block,&newmask,&oldmask);

   alarm(nsecs);

   suspmask = oldmask;

/*make sure sigalrm isn'tblocked*/

   sigdelset(&suspmask,sigalrm);

sigsuspend(&suspmask);/*waitfor any signal to be caught*/

/*some signal has bencaught,sigalrm is now blocked*/

  unslept = alarm(0);

   sigaction(sigalrm,&oldact,null);/*resetprevious action*/

/*reset signal mask,whichunblocks sigalrm*/

   sigprocmask(sig_setmask,&oldmask,null);

   return(unslept);

int main(void) {

while(1)

    sleep(2);

printf("two secondspassed\n");