Linux下当向一个进程发出信号时,从信号产生到进程接收该信号并执行相应操作的过程称为信号的等待过程(呃,根据对APUE的理解翻译的)。如果某一个信号没有被进程屏蔽,则我们可以在程序中阻塞进程对该信号所相应的操作。例如一个程序当接收到SIGUSR1信号时会进行一个操作,我们可以利用系统API阻塞(block)程序对该信号的操作,直到我们解除阻止。再举个现实的例子:就好像一个同学让我帮他带饭,但是我现在有其他事要做,现在我先做我手头上的事,直到我把手上的事都完成才去帮他带饭。整个过程差不多就是这样子。
我们考虑多线程与非多线程的情况。
下来我们来看一段代码,这个程序接收到usr1,usr2信号会设置两个全局变量usr1和usr2的值为1。主程序中有两个循环,第一个循环接收到usr1信号会跳出循环,第二个循环接收到usr1,usr2信号都会跳出循环。
1 #include<stdio.h>
2 #include<signal.h>
3 #include<unistd.h>
4
5 int flag_sigusr1 = 0;
6 int flag_sigusr2 = 0;
7
8 void sig_usr1(int signo){
9 fprintf(stdout, "caught SIGUSR1\n");
10 flag_sigusr1 = 1;
11 return;
12 }
13
14 void sig_usr2(int signo){
15 fprintf(stdout, "caught SIGUSR2\n");
16 flag_sigusr2 = 1;
17 return;
18 }
19
20 int main(void){
21 sigset_t newmask, oldmask;
22
23 signal(SIGUSR1, sig_usr1);
24 signal(SIGUSR2, sig_usr2);
25
26 fprintf(stdout, "first while. catch sigusr1 can break\n");
27 while(1){
28 if(flag_sigusr1){
29 fprintf(stdout, "break");
30 break;
31 }
32 sleep(10);
33 }
34 flag_sigusr1 = 0;
35
36 //block SIGUSR1
37 sigemptyset(&newmask);
38 sigaddset(&newmask, SIGUSR1);
39 if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0){
40 perror("sigprocmask error");
41 }
42
43 fprintf(stdout, "first while. catch sigusr1 or sigusr2 can break\n");
44 while(1){
45 if(flag_sigusr1 || flag_sigusr2){
46 fprintf(stdout, "break");
47 break;
48 }
49 sleep(10);
50 }
51
52 return 0;
53 }
第一个循环和第二个循环之间我们选择阻塞sigusr1信号,所以当程序运行到第二个循环时向程序发送usr1信号时并不会跳出循环。
多线程情况下每个线程共用信号处理函数,但是每个线程可以选择自己是否block某个信号。
再看一个多线程的例子:子线程的功能同上,主线程接收到hup信号会向子线程发送usr2信号。
1 #include<stdio.h>
2 #include<signal.h>
3 #include<unistd.h>
4 #include<pthread.h>
5
6 int flag_sigusr1 = 0;
7 int flag_sigusr2 = 0;
8 int flag_sighup = 0;
9
10 void sig_usr1(int signo){
11 fprintf(stdout, "sig|caught SIGUSR1\n");
12 flag_sigusr1 = 1;
13 return;
14 }
15
16 void sig_usr2(int signo){
17 fprintf(stdout, "sig|caught SIGUSR2\n");
18 flag_sigusr2 = 1;
19 return;
20 }
21
22 void sig_hup(int signo){
23 fprintf(stdout, "sig|caught SIGHUP\n");
24 flag_sighup = 1;
25 return;
26 }
27
28 void *thread_control_signal(void *arg){
29 sigset_t newmask, oldmask;
30 sigemptyset(&newmask);
31
32 //thread block sighup
33 sigemptyset(&newmask);
34 sigaddset(&newmask, SIGHUP);
35 if(pthread_sigmask(SIG_BLOCK, &newmask, &oldmask) < 0){
36 perror("sigprocmask error");
37 }
38
39 fprintf(stdout, "thread|first while. catch sigusr1 or sigusr2 can break\n");
40 while(1){
41 if(flag_sigusr1 || flag_sigusr2){
42 fprintf(stdout, "thread|break\n");
43
44 break;
45 }
46 sleep(10);
47 }
48 flag_sigusr1 = 0;
49
50 //thread block SIGUSR1
51 sigaddset(&newmask, SIGUSR1);
52 if(pthread_sigmask(SIG_BLOCK, &newmask, &oldmask) < 0){
53 perror("sigprocmask error");
54 }
55
56 fprintf(stdout, "thread|first while. catch sigusr2 can break\n");
57 while(1){
58 if(flag_sigusr1 || flag_sigusr2){
59 fprintf(stdout, "break\n");
60 break;
61 }
62 sleep(10);
63 }
64
65 fprintf(stdout, "thread|thread exit\n");
66 return (void *)0;
67 }
68
69 int main(void){
70 sigset_t newmask;
71 pthread_t tid;
72 int signo;
73
74 //signal action
75 signal(SIGUSR1, sig_usr1);
76 signal(SIGUSR2, sig_usr2);
77 signal(SIGHUP , sig_hup);
78
79 if(pthread_create(&tid, NULL, thread_control_signal, NULL) < 0){
80 perror("create pthread failed");
81 return -1;
82 }
83
84 //main thread block sigusr1
85 sigemptyset(&newmask);
86 sigaddset(&newmask, SIGUSR1);
87 if(pthread_sigmask(SIG_BLOCK, &newmask, NULL) < 0){
88 perror("sigprocmask error");
89 }
90
91 //main thread wait sighup
92 sigemptyset(&newmask);
93 sigaddset(&newmask, SIGHUP);
94 if(sigwait(&newmask, &signo) < 0){
95 perror("sigwait failed");
96 return -1;
97 }
98 fprintf(stdout, "main|get SIGHUP\n");
99
100 pthread_kill(tid, SIGUSR2);
101 pthread_kill(tid, SIGUSR2);
102 pthread_join(tid, NULL);
103
104 fprintf(stdout, "main|exit\n");
105 return 0;
106 }
over~