sigsuspend函數作用 :如果在等待信號發生時希望去休眠,則使用sigsuspend函數是非常合適的
頭文件:#include <signal.h>
一個保護臨界區代碼的錯誤實例:(sigprocmask()和pause()實現)
#include <unistd.h> #include <signal.h> #include <stdio.h> void handler(int sig) //信號處理函數的實現 { printf("SIGINT sig"); } int main() { sigset_t new,old; struct sigaction act; act.sa_handler = handler; //信號處理函數handler sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, 0); //准備捕捉SIGINT信號 sigemptyset(&new); sigaddset(&new, SIGINT); sigprocmask(SIG_BLOCK, &new, &old); //將SIGINT信號阻塞,同時保存當前信號集 printf("Blocked"); sigprocmask(SIG_SETMASK, &old, NULL); //取消阻塞 pause(); return 0; }上面實例的問題是:本來期望pause()之後,來SIGINT信號,可以結束程序;可是,如果當“取消阻塞”和“pause”之間,正好來了SIGINT信號,結果程序因為pause的原因會一直掛起。。。
如果在信號阻塞時將其發送給進程,那麼該信號的傳遞就被推遲直到對它解除了阻塞。對應用程序而言,該信號好像發生在解除對SIGINT的阻塞和pause之間。如果發生了這種情況,或者如果在解除阻塞時刻和pause之間確實發生了信號,那麼就產生了問題。因為我們可能不會再見到該信號,所以從這種意義上而言,在此時間窗口(解除阻塞和pause之間)中發生的信號丟失了,這樣就使pause永遠阻塞。
為了糾正此問題,需要在一個原子操作中先恢復信號屏蔽字,然後使進程休眠。這種功能是由sigsuspend函數提供的。
#include <signal.h> int sigsuspend( const sigset_t *sigmask ); 返回值:-1,並將errno設置為EINTR將進程的信號屏蔽字設置為由sigmask指向的值。在捕捉到一個信號或發生了一個會終止該進程的信號之前,該進程被掛起。如果捕捉到一個信號而且從該信號處理程序返回,則sigsuspend返回,並且將該進程的信號屏蔽字設置為調用sigsuspend之前的值。
注意,此函數沒有成功返回值。如果它返回到調用者,則總是返回-1,並將errno設置為EINTR(表示一個被中斷的系統調用)。
3)使用sigsuspend()的程序
#include <unistd.h> #include <signal.h> #include <stdio.h> void handler(int sig) //信號處理程序 { if(sig == SIGINT) printf("SIGINT sig"); else if(sig == SIGQUIT) printf("SIGQUIT sig"); else printf("SIGUSR1 sig"); } int main() { sigset_t new,old,wait; //三個信號集 struct sigaction act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, 0); //可以捕捉以下三個信號:SIGINT/SIGQUIT/SIGUSR1 sigaction(SIGQUIT, &act, 0); sigaction(SIGUSR1, &act, 0); sigemptyset(&new); sigaddset(&new, SIGINT); //SIGINT信號加入到new信號集中 sigemptyset(&wait); sigaddset(&wait, SIGUSR1); //SIGUSR1信號加入wait sigprocmask(SIG_BLOCK, &new, &old); //將SIGINT阻塞,保存當前信號集到old中 //臨界區代碼執行 if(sigsuspend(&wait) != -1) //程序在此處掛起;用wait信號集替換new信號集。即:過來SIGUSR1信 號,阻塞掉,程序繼續掛起;過來其他信號,例如SIGINT,則會喚醒程序。執行sigsuspend的原子操作。注意:如果“sigaddset(&wait, SIGUSR1);”這句沒有,則此處不會阻塞任何信號,即過來任何信號均會喚醒程序。 printf("sigsuspend error"); printf("After sigsuspend"); sigprocmask(SIG_SETMASK, &old, NULL); return 0; }sigsuspend的原子操作是:
(1)設置新的mask阻塞當前進程(上面是用wait替換new,即阻塞SIGUSR1信號)
(2)收到SIGUSR1信號,阻塞,程序繼續掛起;收到其他信號,恢復原先的mask(即包含SIGINT信號的)。
(3)調用該進程設置的信號處理函數(程序中如果先來SIGUSR1信號,然後過來SIGINT信號,則信號處理函數會調用兩次,打印不同的內容。第一次打印SIGINT,第二次打印SIGUSR1,因為SIGUSR1是前面阻塞的)
(4)待信號處理函數返回,sigsuspend返回了。(sigsuspend將捕捉信號和信號處理函數集成到一起了)
注:sigsuspend實際是將sigprocmask和pause結合起來原子操作。
轉自:http://blog.sina.com.cn/s/blog_6af9566301013xp4.html 和http://www.cnblogs.com/nufangrensheng/category/543313.html