以前在看APUE的時候,就沒有看信號這一章,如今APUE的書還給圖書館了,換了一本linux C程序設計,這本書雖然比APUE還普遍,但是和APUE比起來仍是有差距,中國人老想着用文字去說明問題,不用例子去說明,並且例子不能運行的,例子和例子之間千絲萬縷的關係的 仍是有不少的。總之,我以爲Linux C程序設計還有不少能改進的地方,至少風格,示例是能夠好好改進一下的
[root@server myprogram]# kill -l
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 34) SIGRTMIN 35) SIGRTMIN+1
36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5
40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9
44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13
52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9
56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5
60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1
64) SIGRTMAX
可見,我這裏有64個信號,而且從1開始排序
那麼對於信號的處理是怎麼一回事情呢?其實,進程中對於信號的處理是異步的,無論進程在幹什麼,那麼是個死循環,也會去響應信號,去作信號處理函數
譬如:
int main()
{
while(1) ;
return 0;
}
[root@server myprogram]# gcc -o test test.c
[root@server myprogram]# ./test
當咱們按下Ctrl+c的時候,進程終止,這是進程響應SIGINT信號的結果
爲了更明白一點,咱們這樣作
[root@server myprogram]# gcc -o test test.c
[root@server myprogram]# ./test &
[1] 1790
[root@server myprogram]# kill -SIGSEGV 1790
[root@server myprogram]#
[1]+ Segmentation fault ./test
[root@server myprogram]#
想向進程發送SIGSEGV信號,用kill -SIGSEGV 1790的命令
爲何要enter兩次它才輸出segmentation fault呢?由於在進程1790結束以前已經已經回到了shell提示符,等待用戶輸入下一條命令,shell不但願段錯誤的信息和用戶的輸入交錯在一塊兒,因此等待用戶輸入命令之後才顯示進程發生了段錯誤,而且生成一個core文件。
下面看一個示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void sigusr_handler(int signo)//用戶信號1和用戶信號2的處理函數
{
switch(signo)
{
case SIGUSR1:
printf(
"Parent : catch SIGUSR1\n");
break;
case SIGUSR2:
printf(
"Child : catch SIGUSR2\n");
break;
default:
printf(
"should not be here\n");
break;
}
return ;
}
int main(void)
{
pid_t ppid, cpid;
if(signal(SIGUSR1, sigusr_handler) == SIG_ERR)
{
perror(
"can't set handler for SIGUSR1");
exit(1);
}
if(signal(SIGUSR2, sigusr_handler) == SIG_ERR)
{
perror(
"can't set handler for SIGUSR2");
exit(1);
}
ppid = getpid();//後去進程ID
if((cpid = fork()) <0)//fork建立子進程
{
perror(
"fail to fork");
exit(1);
}
else
if(cpid == 0)//在子進程中
{
printf(
"child\n");
if(kill(ppid, SIGUSR1) == -1)//往父進程發SIGUSR1信號
{
perror(
"fail to send signal");
exit(1);
}
while(1) ;
}
else//在父進程中
{
//printf(
"parent\n");
sleep(1);
if(kill(cpid, SIGUSR2) == -1)//往子進程中發SIGUSR2信號
{
perror(
"fail to send signal");
exit(1);
}
printf(
"kill child\n");
if(kill(cpid, SIGKILL) == -1)//kill子進程
{
perror(
"fail to send signal");
exit(1);
}
if(wait(
NULL) == -1)//等待一個子進程退出
{
perror(
"fail to wait");
exit(1);
}
}
return 0;
}
信號是有限的,咱們不能隨便定義本身的信號,有兩個信號是留給用戶本身用的,分別是SIGUSR1,SIGUSR2。
這個例子實現了發送信號,信號處理函數的應用
程序執行結果以下:
[root@server myprogram]# gcc -o test test.c
[root@server myprogram]# ./test
child
Parent : catch SIGUSR1
kill child
Child : catch SIGUSR2
有趣的是,若是我只是掉printf("child");這一句,那麼Child : catch SIGUSR2這一句也打印不出來,等哪位知道緣由的仁兄指教。。。