信號通信編程實(shí)踐
簡(jiǎn)單的說(shuō),信號就是在軟件層次上對中斷機制的一種模擬,是一種異步通信方式。它可以實(shí)現內核進(jìn)程和用戶(hù)進(jìn)程之間的交互。實(shí)現方式是,在任何時(shí)候發(fā)給某一進(jìn)程,如果該進(jìn)程沒(méi)有處于執行態(tài),則該信號由內核保存,直到該進(jìn)程恢復執行再傳遞給它為止。如果一個(gè)信號進(jìn)程設置為阻塞,則該信號的傳遞被延遲,直到其阻塞被取消時(shí)才被傳遞給進(jìn)程。
使用kill -l選項列出系統所支持的所有信號列表。我的Redhat 9.0上如下:
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD
18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN
22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO
30) SIGPWR 31) SIGSYS 33) SIGRTMIN 34) SIGRTMIN+1
35) SIGRTMIN+2 36) SIGRTMIN+3 37) SIGRTMIN+4 38) SIGRTMIN+5
39) SIGRTMIN+6 40) SIGRTMIN+7 41) SIGRTMIN+8 42) SIGRTMIN+9
43) SIGRTMIN+10 44) SIGRTMIN+11 45) SIGRTMIN+12 46) SIGRTMIN+13
47) SIGRTMIN+14 48) SIGRTMIN+15 49) SIGRTMAX-14 50) SIGRTMAX-13
51) SIGRTMAX-12 52) SIGRTMAX-11 53) SIGRTMAX-10 54) SIGRTMAX-9
55) SIGRTMAX-8 56) SIGRTMAX-7 57) SIGRTMAX-6 58) SIGRTMAX-5
59) SIGRTMAX-4 60) SIGRTMAX-3 61) SIGRTMAX-2 62) SIGRTMAX-1
63) SIGRTMAX
可見(jiàn)信號值在31號前的有不同的名稱(chēng),這些是不可靠信號(非實(shí)時(shí)信號);后面的都是以SIGRTMIN或者SIGRTMAX開(kāi)頭的信號,這些是為了解決前面“不可靠信號”的問(wèn)題而進(jìn)行了更改和擴充的信號,也稱(chēng)為實(shí)時(shí)信號。其中RT就是Real Time的簡(jiǎn)寫(xiě)形式。
1、信號的生命周期
一個(gè)完整的信號生命周期可以分為3個(gè)重要階段,這三個(gè)重要階段由4個(gè)重要事件來(lái)刻畫(huà):信號產(chǎn)生、信號在進(jìn)程中注冊、信號在進(jìn)程中注銷(xiāo)、執行信號處理函數。相鄰兩個(gè)事件的時(shí)間間隔構成信號生命周期的一個(gè)階段。
2、信號處理過(guò)程
一個(gè)不可靠信號的處理過(guò)程如下:若發(fā)現該信號已經(jīng)在進(jìn)程中注冊,就忽略該信號,所以,若前一個(gè)信號還未注銷(xiāo)又產(chǎn)生了相同的信號就會(huì )造成信號丟失。
一個(gè)可靠信號的處理過(guò)程如下:可靠信號發(fā)送給進(jìn)程,不管該信號是否已經(jīng)在進(jìn)程中注冊,都會(huì )被再注冊一次,因此信號不會(huì )丟失。
所有可靠信號都支持排隊,而不可靠信號不支持排隊。
3、用戶(hù)進(jìn)程對信號的響應形式
(1)忽略信號,除SIGKILL、SIGSTOP。
(2)捕捉信號,定義信號處理函數,當信號發(fā)生則執行相應的處理函數。
(3)缺省操作。
4、信號發(fā)送函數
kill() raise() alarm() pause()
實(shí)例一:保證子進(jìn)程不在父進(jìn)程調用kill之前退出
/*
* kill.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
/*child*/
else if (pid == 0) {
raise(SIGSTOP);
exit(0);
}
/*father*/
else {
printf("pid = %dn", pid);
if (waitpid(pid, NULL, WNOHANG) == 0) {
if (kill(pid, SIGKILL) == 0) {
printf("kill %dn", pid);
}
else {
perror("kill");
exit(1);
}
}/*if*/
}/*else*/
return 0;
}
執行結果:
[armlinux@lqm kill]$ ./mykill
pid = 2032
kill 2032
實(shí)例二:利用alarm完成sleep功能
/*
* alarm.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void my_alarm_handle(int sign_no)
{
if (sign_no == SIGALRM) {
printf("I have been waken up.n");
}
}
int main()
{
printf("sleep for 5s ... ...n");
signal(SIGALRM, my_alarm_handle);
alarm(5);
pause();
return 0;
}
執行結果:
[armlinux@lqm alarm]$ ./myalarm
sleep for 5s ... ...
等待5秒鐘后執行處理函數,打印輸出下面內容:
I have been waken up.
5、信號處理集函數組
sigemptyset:初始化信號集合為空
sigfillset:初始化信號集合為所有信號的集合
sigaddset:將指定信號加入到信號集合中去
sigdelset:將指定信號從信號集中刪去
sigismember:查詢(xún)指定信號是否在信號集合之中
sigprocmask:判斷檢測或更改信號屏蔽字
sigaction:用于改變進(jìn)程接收到特定信號之后的行為
實(shí)踐三:練習信號處理集函數
/*
* 信號集函數組練習
* 數據結構sigaction
* struct sigaction {
* void (*sa_handler)(int signo);
* sigset_t sa_mask;
* int sa_flags;
* void (*sa_restore)(void);
* }
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
/*自定義SIGINT的處理函數,如果你按ctrl+c,則會(huì )打印提示,而不是默認的退出*/
void my_func(int sigo_num)
{
printf("If you want to quit, please try 'ctrl+\' .n");
}
int main()
{
sigset_t set;
struct sigaction action1, action2;
/*初始化信號集為空*/
if (sigemptyset(&set) < 0) {
perror("sigemptyset");
exit(1);
}
/*將相應的信號加入信號集*/
if (sigaddset(&set, SIGQUIT) < 0) {
perror("sigaddset SIGQUIT");
exit(1);
}
if (sigaddset(&set, SIGINT) < 0) {
perror("sigaddset SIGINT");
exit(1);
}
/*設置信號屏蔽字*/
if (sigprocmask(SIG_BLOCK, &set, NULL) < 0) {
perror("sigprocmask SIG_BLOCK");
exit(1);
}
else {
printf("blocked,and sleep for 5s ...n");
sleep(5);
}
if (sigprocmask(SIG_UNBLOCK, &set, NULL) < 0) {
perror("sigprocmask SIG_UNBLOCK");
exit(1);
}
else {
printf("unblockn");
/*此處可以添加函數功能模塊process()*/
sleep(2);
printf("If you want to quit this program, please try ...n");
}
/*對相應的信號進(jìn)行循環(huán)處理*/
while (1) {
if (sigismember(&set, SIGINT)) {
sigemptyset(&action1.sa_mask);
action1.sa_handler = my_func;
sigaction(SIGINT, &action1, NULL);
}
else if (sigismember(&set, SIGQUIT)) {
sigemptyset(&action2.sa_mask);
/*SIG_DFL采用缺省的方式處理*/
action2.sa_handler = SIG_DFL;
sigaction(SIGTERM, &action2, NULL);
}
}
return 0;
}
執行處理:
[armlinux@lqm sigaction]$ ./sigaction
blocked,and sleep for 5s ...
unblock
If you want to quit this program, please try ...
If you want to quit, please try 'ctrl+' .
退出
評論