signal的作用是什么?会不会导致阻塞?handler函数会在什么情况下调用?使用同一个handler去注册不同的信号,效果怎么样?
161// signal的函数的作用是注册信号的处理行为:
2// 我们可以通过signal函数把某一个可注册行为信号的信号处理模式改为:
3// 1, 改为忽略: signal(信号宏/信号值, SIG_IGN)
4// 2, 改为默认处理模式: signal(信号宏/信号值, SIG_DFL)
5// 3, 改为执行某些信号处理函数: signal(信号宏/信号值, 函数名)
6
7// signal函数只是注册信号的处理行为, signal函数本身不会导致阻塞
8
9// 假设我们通过signal函数注册了一个信号: signal(信号宏/信号值, handler函数):
10// 当注册的信号触发的时候, 会执行这个handler函数, 否则不执行, 这个signal函数的注册的函数是一种回到机制
11
12// 使用同一个handler去注册不同的信号:
13// eg: (假设把2号信号和3号信号的处理函数都注册为, func函数)
14// signal(2, func);
15// signal(3, func);
16// 这会导致, 无论2号信号产生或者3号信号产生, 都会去执行func函数
信号递送过程中,产生了另一个同类信号会怎么样?产生了另两个、三个、多个同类信号会怎么样?写代码验证一下你的想法。说明mask和pending如何变化。
41// 信号递送过程中,产生了另一个同类信号, 这个同类信号并不会立即处理, 要等上一个同类信号执行完毕之后, 这个新来的同类信号才能执行.
2
3// 信号递送过程中,产生了又产生了另两个、三个、多个同类信号, 和额外产生一个同类信号最终执行结果相同, 因为在一个进程中信号是靠位图存储, 一个同类信号共用同一个bit位, 所以同时有两个或者更多的同类信号到来,改变的是同一个bit位.
4
321void func(int num){
2
3printf("signal %d begin \n", num);
4sleep(10);
5
6sigset_t set;
7sigemptyset(&set);
8sigpending(&set);
9if(sigismember(&set, 2)){
10printf("2号信号未决 \n");
11}
12
13sigemptyset(&set);
14sigset_t oldset;
15sigemptyset(&oldset);
16// 目的: 获取当前的mask掩码状态 (通过 oldset )
17sigprocmask(SIG_UNBLOCK, &set, &oldset);
18if(sigismember(&oldset, 2)){
19printf("2号信号在掩码中被设置了阻塞 \n");
20}
21if(sigismember(&oldset, 3)){
22printf("3号信号在掩码中被设置了阻塞 \n");
23}
24
25printf("signal %d over \n", num);
26}
27int main(){
28signal(2, func);
29
30while(1);
31return 0;
32}
131// 第一次的运行结果
2^Csignal 2 begin
3^C2号信号未决
42号信号在掩码中被设置了阻塞
5signal 2 over
6signal 2 begin
72号信号在掩码中被设置了阻塞
8signal 2 over
9
10// 第二次的运行结果
11^Csignal 2 begin
122号信号在掩码中被设置了阻塞
13signal 2 over
21// 通过上述第一次运行结果: 说明一个2信号正在执行的时候, 一个信号2号信号过来, 会在进程task_struct中记录信号pengding字段上中的signal所表示的位图上, 把2号信号的对应bit位标记为信号存在状态
2// 同时, 通过第一次和第二次运行结果, 我们通过获取当前mask掩码, 都发现2号信号在处理的时候, 会在mask上把2号信号对应bit位设置为阻塞状态, 用以阻塞新到来的2号信号
使用sigaction注册2号信号的处理函数
1) 允许自动重启低速系统调用
2)在处理2号信号时阻塞3号信号,不会被3号信号打断;
在2号信号的信号处理函数中,使用sigpending函数判断一下有没有3号信号处于未决状态;
411
2void func(int num){
3printf("func run \n");
4
5sleep(10);
6
7// 2号信号的信号处理函数中,使用sigpending函数判断一下有没有3号信号处于未决状态
8sigset_t pending;
9sigemptyset(&pending);
10sigpending(&pending);
11if(sigismember(&pending, 3)){
12printf("在当前的2号信号处理逻辑中, 有一个3号信号已经到啦, 被屏蔽了 \n");
13}
14
15printf("func over \n");
16}
17int main(int argc,char*argv[])
18{
19
20struct sigaction act , old;
21memset(&act, 0, sizeof(act));
22memset(&old, 0, sizeof(old));
23
24act.sa_handler = func;
25// 重启系统调用(如下read函数)
26act.sa_flags = SA_RESTART;
27
28// 设置处理2号信号时阻塞3号信号
29sigset_t set;
30sigemptyset(&set);
31sigaddset(&set, 3);
32act.sa_mask = set;
33
34sigaction(2, &act, &old);
35
36char buf[60] = {0};
37read(STDIN_FILENO, buf, sizeof(buf));
38printf("buf: %s \n", buf);
39
40return 0;
41}
通过sigprocmask阻塞2号信号,睡眠5秒后,解除阻塞,2号信号得到执行;在睡眠后,解除阻塞之前,通过sigpending检测是否有信号挂起。
251int main(int argc,char*argv[])
2{
3
4// 通过sigprocmask阻塞2号信号
5sigset_t set, old;
6sigemptyset(&set);
7sigemptyset(&old);
8sigaddset(&set, 2);
9sigprocmask(SIG_BLOCK, &set, &old);
10
11sleep(5);
12// 在睡眠后,解除阻塞之前,通过sigpending检测是否有信号挂起。
13sigset_t pending;
14sigemptyset(&pending);
15sigpending(&pending);
16if(sigismember(&pending, 2)){
17printf("2号信号未决 \n");
18}
19
20// 睡眠5秒后,解除阻塞
21sigprocmask(SIG_UNBLOCK, &set, &old);
22
23while(1);
24return 0;
25}
完成窗口聊天: 通信方式: - A进程和B进程负责通信,从标准输入读到的字符串通过管道发给对方 - A进程从标准输入读到的字符串发给B进程后,B打印到屏幕上。 - B进程从标准输入读到的字符串发给A进程,A打印到屏幕上。 退出方式: 任意一个进程在标准输入收到输入1,给所有进程(通信双方)发送10号信号,每个进程收到10号信号后,开始执行有序退出
551// A
2void func(int num){
3printf("func num: %d \n", num);
4exit(0);
5}
6int main(int argc,char*argv[])
7{
8signal(10, func);
9
10int pipe_write = open("1.pipe", O_WRONLY);
11int pipe_read = open("2.pipe", O_RDONLY);
12
13// 拿到双方pid
14int pid_a = getpid();
15int pid_b;
16read(pipe_read, &pid_b, sizeof(int));
17write(pipe_write, &pid_a, sizeof(int));
18
19fd_set set;
20FD_ZERO(&set);
21
22while(1){
23FD_SET(STDIN_FILENO, &set);
24FD_SET(pipe_read, &set);
25
26select(10, &set, NULL, NULL, NULL);
27
28if(FD_ISSET(STDIN_FILENO, &set)){
29char buf[60] = {0};
30bzero(buf, sizeof(buf));
31int res = read(STDIN_FILENO, buf, sizeof(buf));
32// 任意一个进程在标准输入收到输入1,给所有进程(通信双方)发送10号信号
33if(res==2 && atoi(buf)==1){
34kill(pid_b, 10);
35kill(pid_a, 10);
36return 0;
37}
38write(pipe_write, buf, sizeof(buf));
39}
40if(FD_ISSET(pipe_read, &set)){
41char buf[60] = {0};
42bzero(buf, sizeof(buf));
43int res = read(pipe_read, buf, sizeof(buf));
44if(res == 0){
45printf("对端关闭了管道 \n");
46break;
47}
48printf("B: %s \n", buf);
49}
50}
51
52close(pipe_read);
53close(pipe_write);
54return 0;
55}
xxxxxxxxxx
691// B
2void func(int num){
3printf("signal num: %d \n", num);
4exit(0);
5}
6int main(int argc,char*argv[])
7{
8signal(10, func);
9
10int pipe_read = open("1.pipe", O_RDONLY);
11int pipe_write = open("2.pipe", O_WRONLY);
12
13int pid_a;
14int pid_b = getpid();
15write(pipe_write, &pid_b, sizeof(int));
16read(pipe_read, &pid_a, sizeof(int));
17
18fd_set set;
19FD_ZERO(&set);
20
21struct timeval tv;
22tv.tv_sec = 10;
23tv.tv_usec = 0;
24while(1){
25
26FD_SET(STDIN_FILENO, &set);
27FD_SET(pipe_read, &set);
28
29select(10, &set, NULL, NULL, &tv);
30
31if(FD_ISSET(STDIN_FILENO, &set)){
32char buf[60] = {0};
33bzero(buf, sizeof(buf));
34int res = read(STDIN_FILENO, buf, sizeof(buf));
35// 任意一个进程在标准输入收到输入1,给所有进程(通信双方)发送10号信号
36if(res == 2 && atoi(buf) ==1){
37kill(pid_a, 10);
38kill(pid_b, 10);
39
40return 0;
41}
42write(pipe_write, buf, sizeof(buf));
43}
44
45if(FD_ISSET(pipe_read, &set)){
46char buf[60] = {0};
47bzero(buf, sizeof(buf));
48int res = read(pipe_read, buf, sizeof(buf));
49if(res == 0){
50printf("对端关闭了管道 \n");
51break;
52}
53printf("A: %s \n", buf);
54
55tv.tv_sec = 10;
56tv.tv_usec = 0;
57}else{
58if(tv.tv_sec == 0){
59printf("超时断开 \n");
60break;
61}
62}
63
64}
65
66close(pipe_read);
67close(pipe_write);
68return 0;
69}