信號(hào)通信編程實(shí)踐
簡單的說,信號(hào)就是在軟件層次上對(duì)中斷機(jī)制的一種模擬,是一種異步通信方式。它可以實(shí)現(xiàn)內(nèi)核進(jìn)程和用戶進(jìn)程之間的交互。實(shí)現(xiàn)方式是,在任何時(shí)候發(fā)給某一進(jìn)程,如果該進(jìn)程沒有處于執(zhí)行態(tài),則該信號(hào)由內(nèi)核保存,直到該進(jìn)程恢復(fù)執(zhí)行再傳遞給它為止。如果一個(gè)信號(hào)進(jìn)程設(shè)置為阻塞,則該信號(hào)的傳遞被延遲,直到其阻塞被取消時(shí)才被傳遞給進(jìn)程。
使用kill -l選項(xiàng)列出系統(tǒng)所支持的所有信號(hào)列表。我的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
可見信號(hào)值在31號(hào)前的有不同的名稱,這些是不可靠信號(hào)(非實(shí)時(shí)信號(hào));后面的都是以SIGRTMIN或者SIGRTMAX開頭的信號(hào),這些是為了解決前面“不可靠信號(hào)”的問題而進(jìn)行了更改和擴(kuò)充的信號(hào),也稱為實(shí)時(shí)信號(hào)。其中RT就是Real Time的簡寫形式。
1、信號(hào)的生命周期
一個(gè)完整的信號(hào)生命周期可以分為3個(gè)重要階段,這三個(gè)重要階段由4個(gè)重要事件來刻畫:信號(hào)產(chǎn)生、信號(hào)在進(jìn)程中注冊、信號(hào)在進(jìn)程中注銷、執(zhí)行信號(hào)處理函數(shù)。相鄰兩個(gè)事件的時(shí)間間隔構(gòu)成信號(hào)生命周期的一個(gè)階段。
2、信號(hào)處理過程
一個(gè)不可靠信號(hào)的處理過程如下:若發(fā)現(xiàn)該信號(hào)已經(jīng)在進(jìn)程中注冊,就忽略該信號(hào),所以,若前一個(gè)信號(hào)還未注銷又產(chǎn)生了相同的信號(hào)就會(huì)造成信號(hào)丟失。
一個(gè)可靠信號(hào)的處理過程如下:可靠信號(hào)發(fā)送給進(jìn)程,不管該信號(hào)是否已經(jīng)在進(jìn)程中注冊,都會(huì)被再注冊一次,因此信號(hào)不會(huì)丟失。
所有可靠信號(hào)都支持排隊(duì),而不可靠信號(hào)不支持排隊(duì)。
3、用戶進(jìn)程對(duì)信號(hào)的響應(yīng)形式
(1)忽略信號(hào),除SIGKILL、SIGSTOP。
(2)捕捉信號(hào),定義信號(hào)處理函數(shù),當(dāng)信號(hào)發(fā)生則執(zhí)行相應(yīng)的處理函數(shù)。
(3)缺省操作。
4、信號(hào)發(fā)送函數(shù)
kill() raise() alarm() pause()
實(shí)例一:保證子進(jìn)程不在父進(jìn)程調(diào)用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;
}
執(zhí)行結(jié)果:
[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;
}
執(zhí)行結(jié)果:
[armlinux@lqm alarm]$ ./myalarm
sleep for 5s ... ...
等待5秒鐘后執(zhí)行處理函數(shù),打印輸出下面內(nèi)容:
I have been waken up.
5、信號(hào)處理集函數(shù)組
sigemptyset:初始化信號(hào)集合為空
sigfillset:初始化信號(hào)集合為所有信號(hào)的集合
sigaddset:將指定信號(hào)加入到信號(hào)集合中去
sigdelset:將指定信號(hào)從信號(hào)集中刪去
sigismember:查詢指定信號(hào)是否在信號(hào)集合之中
sigprocmask:判斷檢測或更改信號(hào)屏蔽字
sigaction:用于改變進(jìn)程接收到特定信號(hào)之后的行為
實(shí)踐三:練習(xí)信號(hào)處理集函數(shù)
/*
* 信號(hào)集函數(shù)組練習(xí)
* 數(shù)據(jù)結(jié)構(gòu)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的處理函數(shù),如果你按ctrl+c,則會(huì)打印提示,而不是默認(rèn)的退出*/
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;
/*初始化信號(hào)集為空*/
if (sigemptyset(&set) < 0) {
perror("sigemptyset");
exit(1);
}
/*將相應(yīng)的信號(hào)加入信號(hào)集*/
if (sigaddset(&set, SIGQUIT) < 0) {
perror("sigaddset SIGQUIT");
exit(1);
}
if (sigaddset(&set, SIGINT) < 0) {
perror("sigaddset SIGINT");
exit(1);
}
/*設(shè)置信號(hào)屏蔽字*/
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");
/*此處可以添加函數(shù)功能模塊process()*/
sleep(2);
printf("If you want to quit this program, please try ...n");
}
/*對(duì)相應(yīng)的信號(hào)進(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;
}
執(zhí)行處理:
[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+' .
退出
評(píng)論