信號處理函數
sigaction的用法
int sigaction (
????????int signo,
????????const struct sigaction *act,
????????struct sigaction *oldact
);
這個函數主要是用于改變或檢測信號的行為融击。
第一個參數是變更signo指定的信號吗购,它可以指向任何值则拷,SIGKILL,SIGSTOP除外
第二個參數,第三個參數是對信號進行細粒度的控制。
如果*act不為空向叉,*oldact不為空糖权,那么oldact將會存儲信號以前的行為。
如果act為空,*oldact不為空铜幽,那么oldact將會存儲信號現在的行為。
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是一個函數指針串稀,主要是表示接收到信號時所要采取的行動除抛。此字段的值可以是SIG_DFL,SIG_IGN.分別代表默認操作與內核將忽略進程的信號。這個函數只傳遞一個參數那就是信號代碼母截。
當SA_SIGINFO被設定在sa_flags中镶殷,那么則會使用sa_sigaction來指示信號處理函數,而非sa_handler.
sa_mask設置了掩碼集微酬,在程序執(zhí)行期間會阻擋掩碼集中的信號绘趋。
sa_flags設置了一些標志, SA_RESETHAND當該函數處理完成之后颗管,設定為為系統(tǒng)默認的處理模式陷遮。SA_NODEFER 在處理函數中,如果再次到達此信號時垦江,將不會阻塞帽馋。默認情況下,同一信號兩次到達時,如果此時處于信號處理程序中绽族,那么此信號將會阻塞姨涡。
SA_SIGINFO表示用sa_sigaction指示的函數。
sa_restorer已經被廢棄吧慢。
sa_sigaction所指向的函數原型:
void my_handler(int signo, siginfo_t *si, void *ucontext);
第一個參數: 信號編號
第二個參數:指向一個siginfo_t結構涛漂。
第三個參數是一個ucontext_t結構。
其中siginfo_t結構體中包含了大量的信號攜帶信息检诗,可以看出匈仗,這個函數比sa_handler要強大,因為前者只能傳遞一個信號代碼逢慌,而后者可以傳遞siginfo_t信息悠轩。
typedef struct siginfo_t {
????????int si_signo;//信號編號
????????int si_errno;//如果為非零值則錯誤代碼與之關聯
????????int si_code;//說明進程如何接收信號以及從何處收到
????????pid_t si_pid;//適用于SIGCHLD,代表被終止進程的PID
????????pid_t si_uid;//適用于SIGCHLD,代表被終止進程所擁有進程的UID
????????int si_status;//適用于SIGCHLD攻泼,代表被終止進程的狀態(tài)
????????clock_t si_utime;//適用于SIGCHLD火架,代表被終止進程所消耗的用戶時間
????????clock_t si_stime;//適用于SIGCHLD,代表被終止進程所消耗系統(tǒng)的時間
????????sigval_t si_value;
????????int si_int;
????????void * si_ptr;
????????void* si_addr;
????????int si_band;
????????int si_fd;
};
sigqueue的用法
sigqueue( pid_t pid, int signo, const union sigval value)
union sigval? {int sival_int, void*sival_ptr };
sigqueue函數類似于kill,也是一個進程向另外一個進程發(fā)送信號的忙菠。
但它比kill函數強大何鸡。
第一個參數指定目標進程的pid.
第二個參數是一個信號代碼。
第三個參數是一個共用體只搁,每次只能使用一個音比,用來進程發(fā)送信號傳遞的數據俭尖。
或者傳遞整形數據氢惋,或者是傳遞指針。
發(fā)送的數據被sa_sigaction所指示的函數的siginfo_t結構體中的si_ptr或者是si_int所接收稽犁。
sigpending的用法
sigpending(sigset_t set);
這個函數的作用是返回未決的信號到信號集set中焰望。
即未決信號集,未決信號集不僅包括被阻塞的信號已亥,也可能包括已經到達但沒有被處理的信號熊赖。
示例1: sigaction函數的用法
void signal_set1(int x) { //信號處理函數,只傳遞一個參數信號代碼
????????printf("xxxxx/n");
????????while(1)? {
????????????????//
?????????}
}
void signal_set(struct sigaction *act)
{
????????switch(act->sa_flags) {
????????case (int)SIG_DFL:
????????????????printf("using default hander/n");
????????????????break;
????????case (int)SIG_IGN:
????????????????printf("ignore the signal/n");
????????????????break;
????????default:
????????????????printf("%0x/n",act->sa_handler);
????????}
}
int main(int argc, char** argv)
{
????????int i;
????????struct sigaction act,oldact;
????????act.sa_handler = signal_set1;
????????act.sa_flags = SA_RESETHAND;
????????//SA_RESETHANDD 在處理完信號之后虑椎,將信號恢復成默認處理
????????//SA_NODEFER在信號處理程序執(zhí)行期間仍然可以接收信號
????????sigaction (SIGINT,&act,&oldact) ;//改變信號的處理模式
????????for (i=1; i<12; i++)
????????{
????????????????printf("signal %d handler is : ",i);
????????????????sigaction (i,NULL,&oldact) ;
????????????????signal_set(&oldact);//如果act為NULL震鹉,oldact會存儲信號當前的行為
????????????????//act不為空,oldact不為空捆姜,則oldact會存儲信號以前的處理模式
????????}
????????while(1) {
????????????????//等待信號的到來
????????}
????????return 0;
}
運行結果:
[root@localhost C]# ./s2
signal 1 handler is : using default hander
signal 2 handler is : 8048437
signal 3 handler is : using default hander
signal 4 handler is : using default hander
signal 5 handler is : using default hander
signal 6 handler is : using default hander
signal 7 handler is : using default hander
signal 8 handler is : using default hander
signal 9 handler is : using default hander
signal 10 handler is : using default hander
signal 11 handler is : using default hander
xxxxx
解釋:
sigaction(i,NULL,&oldact);
signal_set(&oldact);
由于act為NULL,那么oldact保存的是當前信號的行為传趾,當前的第二個信號的行為是執(zhí)行自定義的處理程序。
當按下CTRL+C時會執(zhí)行信號處理程序泥技,輸出xxxxxx浆兰,再按一下CTRL+C會停止,是由于SA_RESETHAND恢復成默認的處理模式,即終止程序。
如果沒有設置SA_NODEFER,那么在處理函數執(zhí)行過程中按一下CTRL+C將會被阻塞簸呈,那么程序會停在那里榕订。
示例2: sigqueue向本進程發(fā)送數據的信號
void myhandler(int signo, siginfo_t *si, void *ucontext);
int main()? {
????????union sigval val;//定義一個攜帶數據的共用體
????????struct sigaction oldact,act;
????????act.sa_sigaction = myhandler;
????????act.sa_flags = SA_SIGINFO;//表示使用sa_sigaction指示的函數,處理完恢復默認蜕便,不阻塞處理過程中到達下在被處理的信號
????????//注冊信號處理函數
????????sigaction(SIGUSR1, &act, &oldact);
????????char data[100];
????????int num=0;
????????while( num < 10 )? {
????????????????sleep( 2 );
????????????????printf("等待SIGUSR1信號的到來/n");
????????????????sprintf(data, "%d", num++);
????????????????val.sival_ptr=data;
????????????????sigqueue( getpid(), SIGUSR1, val );//向本進程發(fā)送一個信號
????????????}
}
void myhandler ( int signo, siginfo_t *si, void *ucontext )? {
????????printf("已經收到SIGUSR1信號/n");
????????printf("%s/n",(char*)(si->si_ptr));
}
程序執(zhí)行的結果是:
等待SIGUSR1信號的到來
已經收到SIGUSR1信號
0
等待SIGUSR1信號的到來
已經收到SIGUSR1信號
1
等待SIGUSR1信號的到來
已經收到SIGUSR1信號
2
等待SIGUSR1信號的到來
已經收到SIGUSR1信號
3
等待SIGUSR1信號的到來
已經收到SIGUSR1信號
4
等待SIGUSR1信號的到來
已經收到SIGUSR1信號
5
等待SIGUSR1信號的到來
已經收到SIGUSR1信號
6
等待SIGUSR1信號的到來
已經收到SIGUSR1信號
7
等待SIGUSR1信號的到來
已經收到SIGUSR1信號
8
等待SIGUSR1信號的到來
已經收到SIGUSR1信號
9
解釋:?
本程序用sigqueue不停的向自身發(fā)送信號,并且攜帶數據劫恒,數據被放到處理函數的第二個參數siginfo_t結構體中的si_ptr指針,當num<10時不再發(fā)玩裙。
一般而言兼贸,sigqueue與sigaction配合使用,而kill與signal配合使用吃溅。
示例3: 一個進程向另外一個進程發(fā)送信號溶诞,并攜帶信息
發(fā)送端:
int main()? {
????????union sigval value;
????????value.sival_int=10;
????????if ( sigqueue(4403, SIGUSR1, value) == -1 )? {? //4403是目標進程pid
????????????????perror("信號發(fā)送失敗/n");
????????}
????????sleep(2);
}
接收端:
void myhandler ( int signo, siginfo_t*si, void *ucontext );
int main () {
????????struct sigaction oldact, act;
????????act.sa_sigaction = myhandler;
????????act.sa_flags = SA_SIGINFO | SA_NODEFER;
????????//表示執(zhí)行后恢復,用sa_sigaction指示的處理函數决侈,在執(zhí)行期間仍然可以接收信號
????????sigaction ( SIGUSR1, &act, &oldact );
????????while ( 1 )? {
????????????????sleep ( 2 );
????????????????printf("等待信號的到來/n");
????????}
}
void myhandler ( int signo, siginfo_t *si, void *ucontext ) {
????????printf("the value is %d/n",si->si_int);
}
示例4: sigpending的用法
sigpending (sigset_t *set )將未決信號放到指定的set信號集中去螺垢,未決信號包括被阻塞的信號和信號到達時但還沒來得及處理的信號
void myhandler ( int signo, siginfo_t *si, void *ucontext );
int main()? {
????????struct sigaction oldact, act;
????????sigset_t oldmask, newmask, pendingmask;
????????act.sa_sigaction = myhandler;
????????act.sa_flags = SA_SIGINFO;
????????sigemptyset( &act.sa_mask );? //首先將阻塞集合設置為空,即不阻塞任何信號
????????//注冊信號處理函數
????????sigaction(SIGRTMIN + 10, &act ,&oldact);
????????//開始阻塞
????????sigemptyset( &newmask );
????????sigaddset( &newmask, SIGRTMIN + 10);
????????printf("SIGRTMIN + 10 blocked/n");
????????sigprocmask( SIG_BLOCK , &newmask ,&oldmask );
????????sleep(20);? //為了發(fā)出信號
????????printf("now begin to get pending mask/n");
????????if ( sigpending( &pendingmask ) < 0 )? {
????????????????perror("pendingmask error");
????????}
????????if ( sigismember( &pendingmask, SIGRTMIN + 10 ) )? {
????????????????printf("SIGRTMIN+10 is in the pending mask/n");
????????}
????????sigprocmask( SIG_UNBLOCK, &newmask, &oldmask);
? ? ? ? printf("SIGRTMIN+10 unblocked/n");
}
//信號處理函數
void myhandler ( int signo, siginfo_t *si, void *ucontext )? {
????????printf("receive signal %d/n",si->si_signo);
}
程序執(zhí)行:
在另一個shell發(fā)送信號:
kill -44 4579
SIGRTMIN +10 blocked
now begin to get pending mask
SIGRTMIN +10 is in the pending mask
receive signal 44
SIGRTMIN +10 unblocked
可以看到SIGRTMIN由于被阻塞所以處于未決信號集中赖歌。