signal的作用是什么?会不会导致阻塞?handler函数会在什么情况下调用?使用同一个handler去注册不同的信号,效果怎么样?
161// signal的函数的作用是注册信号的处理行为:2// 我们可以通过signal函数把某一个可注册行为信号的信号处理模式改为:3// 1, 改为忽略: signal(信号宏/信号值, SIG_IGN)4// 2, 改为默认处理模式: signal(信号宏/信号值, SIG_DFL)5// 3, 改为执行某些信号处理函数: signal(信号宏/信号值, 函数名)67// signal函数只是注册信号的处理行为, signal函数本身不会导致阻塞89// 假设我们通过signal函数注册了一个信号: signal(信号宏/信号值, handler函数):10// 当注册的信号触发的时候, 会执行这个handler函数, 否则不执行, 这个signal函数的注册的函数是一种回到机制1112// 使用同一个handler去注册不同的信号:13// eg: (假设把2号信号和3号信号的处理函数都注册为, func函数)14// signal(2, func);15// signal(3, func);16// 这会导致, 无论2号信号产生或者3号信号产生, 都会去执行func函数
信号递送过程中,产生了另一个同类信号会怎么样?产生了另两个、三个、多个同类信号会怎么样?写代码验证一下你的想法。说明mask和pending如何变化。
41// 信号递送过程中,产生了另一个同类信号, 这个同类信号并不会立即处理, 要等上一个同类信号执行完毕之后, 这个新来的同类信号才能执行.23// 信号递送过程中,产生了又产生了另两个、三个、多个同类信号, 和额外产生一个同类信号最终执行结果相同, 因为在一个进程中信号是靠位图存储, 一个同类信号共用同一个bit位, 所以同时有两个或者更多的同类信号到来,改变的是同一个bit位.4321void func(int num){23printf("signal %d begin \n", num);4sleep(10);56sigset_t set;7sigemptyset(&set);8sigpending(&set);9if(sigismember(&set, 2)){10printf("2号信号未决 \n");11}1213sigemptyset(&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}2425printf("signal %d over \n", num);26}27int main(){28signal(2, func);2930while(1);31return 0;32}131// 第一次的运行结果2^Csignal 2 begin3^C2号信号未决42号信号在掩码中被设置了阻塞5signal 2 over6signal 2 begin72号信号在掩码中被设置了阻塞8signal 2 over910// 第二次的运行结果11^Csignal 2 begin122号信号在掩码中被设置了阻塞13signal 2 over21// 通过上述第一次运行结果: 说明一个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号信号处于未决状态;
4112void func(int num){3printf("func run \n");45sleep(10);67// 2号信号的信号处理函数中,使用sigpending函数判断一下有没有3号信号处于未决状态8sigset_t pending;9sigemptyset(&pending);10sigpending(&pending);11if(sigismember(&pending, 3)){12printf("在当前的2号信号处理逻辑中, 有一个3号信号已经到啦, 被屏蔽了 \n");13}1415printf("func over \n");16}17int main(int argc,char*argv[])18{1920struct sigaction act , old;21memset(&act, 0, sizeof(act));22memset(&old, 0, sizeof(old));2324act.sa_handler = func;25// 重启系统调用(如下read函数)26act.sa_flags = SA_RESTART;2728// 设置处理2号信号时阻塞3号信号29sigset_t set;30sigemptyset(&set);31sigaddset(&set, 3);32act.sa_mask = set;3334sigaction(2, &act, &old);3536char buf[60] = {0};37read(STDIN_FILENO, buf, sizeof(buf));38printf("buf: %s \n", buf);3940return 0;41}
通过sigprocmask阻塞2号信号,睡眠5秒后,解除阻塞,2号信号得到执行;在睡眠后,解除阻塞之前,通过sigpending检测是否有信号挂起。
251int main(int argc,char*argv[])2{34// 通过sigprocmask阻塞2号信号5sigset_t set, old;6sigemptyset(&set);7sigemptyset(&old);8sigaddset(&set, 2);9sigprocmask(SIG_BLOCK, &set, &old);1011sleep(5);12// 在睡眠后,解除阻塞之前,通过sigpending检测是否有信号挂起。13sigset_t pending;14sigemptyset(&pending);15sigpending(&pending);16if(sigismember(&pending, 2)){17printf("2号信号未决 \n");18}1920// 睡眠5秒后,解除阻塞21sigprocmask(SIG_UNBLOCK, &set, &old);2223while(1);24return 0;25}
完成窗口聊天: 通信方式: - A进程和B进程负责通信,从标准输入读到的字符串通过管道发给对方 - A进程从标准输入读到的字符串发给B进程后,B打印到屏幕上。 - B进程从标准输入读到的字符串发给A进程,A打印到屏幕上。 退出方式: 任意一个进程在标准输入收到输入1,给所有进程(通信双方)发送10号信号,每个进程收到10号信号后,开始执行有序退出
551// A2void func(int num){3printf("func num: %d \n", num);4exit(0);5}6int main(int argc,char*argv[])7{8signal(10, func);910int pipe_write = open("1.pipe", O_WRONLY);11int pipe_read = open("2.pipe", O_RDONLY);1213// 拿到双方pid14int pid_a = getpid();15int pid_b;16read(pipe_read, &pid_b, sizeof(int));17write(pipe_write, &pid_a, sizeof(int));1819fd_set set;20FD_ZERO(&set);2122while(1){23FD_SET(STDIN_FILENO, &set);24FD_SET(pipe_read, &set);2526select(10, &set, NULL, NULL, NULL);2728if(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}5152close(pipe_read);53close(pipe_write);54return 0;55}xxxxxxxxxx691// B2void func(int num){3printf("signal num: %d \n", num);4exit(0);5}6int main(int argc,char*argv[])7{8signal(10, func);910int pipe_read = open("1.pipe", O_RDONLY);11int pipe_write = open("2.pipe", O_WRONLY);1213int pid_a;14int pid_b = getpid();15write(pipe_write, &pid_b, sizeof(int));16read(pipe_read, &pid_a, sizeof(int));1718fd_set set;19FD_ZERO(&set);2021struct timeval tv;22tv.tv_sec = 10;23tv.tv_usec = 0;24while(1){2526FD_SET(STDIN_FILENO, &set);27FD_SET(pipe_read, &set);2829select(10, &set, NULL, NULL, &tv);3031if(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);3940return 0;41}42write(pipe_write, buf, sizeof(buf));43}4445if(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);5455tv.tv_sec = 10;56tv.tv_usec = 0;57}else{58if(tv.tv_sec == 0){59printf("超时断开 \n");60break;61}62}6364}6566close(pipe_read);67close(pipe_write);68return 0;69}