apue2 第十章 信号:Unix/Linux信号阻塞(sigaction sigprocmask sigsuspend)
来源:互联网 发布:sql语句升序降序列题 编辑:程序博客网 时间:2024/06/06 07:59
#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>#include <errno.h>void sig_int(int);intmain(int argc, char *argv[]){ sigset_t new_mask; struct sigaction act; sigemptyset(&act.sa_mask); act.sa_flags=0; act.sa_handler=sig_int; if (sigaction(SIGINT, &act, NULL)) /* 注册信号SIGINT处理函数为sig_int */ perror("sigaction(SIGINT) error"); if (sigaction(SIGQUIT, &act, NULL)) /* 注册信号SIGQUIT处理函数为sig_int */ perror("sigaction(SIGQUIT) error"); printf("please send signal (SIGINT): kill -s %d %d\n",SIGINT, getpid()); printf("please send signal(SIGQUIT): kill -s %d %d\n",SIGQUIT, getpid()); sigemptyset(&new_mask); /* 查询当前进程被挂起的信号存入new_mask中,可用sigpending(&new_mask)代替 */ if (sigprocmask(0, NULL, &new_mask) < 0) printf("get pending mask error\n"); /* * 将信号SIGQUIT,添加到信号集new_mask中, * 也就是在原有的信号掩码中加入信号SIGQUIT。 * 将当前的信号掩码替换成new_mask, * 也就是把信号SIGQUIT给阻塞后,当前进程挂起。 * 必须等待未阻塞的信号到来才恢复成原来的信号掩码。 * */ sigaddset(&new_mask, SIGQUIT); sigsuspend(&new_mask); exit(0);}voidsig_int(int signum){ if (signum == SIGINT) printf("SIGINT\n"); else if (signum == SIGQUIT) printf("SIGQUIT\n");}编译该程序,并运行。在另一终端向该进程发送信号(运行kill -s SIGQUIT pid,SIGQUIT以及pid具体多少看程序的输出),一直未见到应该打印的信息"SIGQUIT\n",这就说明SIGQUIT信号被阻塞了,当发送SIGINT信号时给该程序时,因为SIGINT信号并未阻塞,所以打印了"SIGINT\n",紧接着sigsuspend恢复原来的信号掩码(原来的信号掩码并未阻塞SIGQUIT信号),最后才打印了刚开始接收到的SIGQUIT信号的信息息"SIGQUIT\n"。具体情况如下:
情况一:
1、程序运行后,执行到sigsuspend函数,用new_mask替换原来的信号掩码,即SIGQUIT信号被阻塞。
2、开启另一终端,执行 kill -s SIGQUIT pid 程序结果如下:
please send signal: kill -s 3 4026
3、这就说明SIGQUIT信号被阻塞了,未见到应该打印的信息"SIGQUIT\n",程序任在被挂起状态。
情况二:
1、程序运行后,执行到sigsuspend函数,用new_mask替换原来的信号掩码,即SIGQUIT信号被阻塞。
2、开启另一终端,执行 kill -s SIGQUIT pid 程序结果如下:
please send signal: kill -s 3 4026
3、这就说明SIGQUIT信号被阻塞了,未见到应该打印的信息"SIGQUIT\n"",程序任在被挂起状态。
4、继续在另一终端上,执行 kill -s SIGINT pid程序结果如下:
please send signal: kill -s 3 4026
SIGINT
SIGQUIT
程序退出
5、这说明sigsuspend恢复原来的信号掩码(原来的信号掩码并未阻塞SIGQUIT信号),最后才打印了刚开始接收到的SIGQUIT信号的信息息"SIGQUIT\n",打印结束程序退出。
#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>#include <errno.h>volatile sig_atomic_t quitflag; /* set nonzero by signal handler */void sig_int(int);intmain(int argc, char *argv[]){ sigset_t new_mask, old_mask, zero_mask; struct sigaction act; quitflag = 0; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = sig_int; if(sigaction(SIGINT, &act, NULL)) /* 注册信号SIGINT处理函数为sig_int */ perror("sigaction(SIGINT) error"); if(sigaction(SIGQUIT, &act, NULL)) /* 注册信号SIGQUIT处理函数为sig_int */ perror("sigaction(SIGQUIT) error"); printf("please send signal (SIGINT): kill -s %d %d\n", SIGINT, getpid()); printf("please send signal(SIGQUIT): kill -s %d %d\n", SIGQUIT, getpid()); sigemptyset(&zero_mask); sigemptyset(&new_mask); sigaddset(&new_mask, SIGQUIT); /* 将信号SIGQUIT,添加到空信号集new_mask中 */ if(sigprocmask(SIG_BLOCK, &new_mask, &old_mask)) /* 把信号SIGQUIT给阻塞 */ perror("SIG_BLOCK error\n"); sigemptyset(&zero_mask); /* 清空信号集zero_mask */ /* * 将当前的信号掩码替换成空信号掩码zero_mask, * 也就是没有任何信号被阻塞,当前进程挂起。 * 等待任意信号到来就可恢复成原来的信号码, * 但是这里有个循环判断当quitflag == 0 时继续挂起当前进程, * 这里呢除了SIGQUIT信号外其它信号都不可以改变quitflag的值。 * */ while(quitflag == 0) sigsuspend(&zero_mask); if(sigprocmask(SIG_SETMASK, &old_mask, NULL)<0) perror("SIG_SETMASK error\n"); exit(0);}voidsig_int(int signum){ if (signum == SIGINT) printf("\nSIGINT\n"); else if (signum == SIGQUIT) { printf("\nSIGQUIT\n"); quitflag = 1; }}
这里程序的情况分三种:
情况一:
1、程序运行后,执行到sigsuspend函数,用空信号掩码zero_mask替换原来的信号掩码,即不阻塞任何信号。
2、开启另一终端,执行 kill -s SIGINT pid 程序结果如下:
please send signal: kill -s 3 4026
SIGINT
3、程序任在被挂起状态,这就说明还在循环中,因为SIGINT信号的处理函数不能更改quitflag的值,仍然不阻塞任何信号。
情况二:
1、程序运行后,执行到sigsuspend函数,用空信号掩码zero_mask替换原来的信号掩码,即不阻塞任何信号。
2、开启另一终端,执行 kill -s SIGINT pid 程序结果如下:
please send signal: kill -s 3 4026
SIGINT
3、程序任在被挂起状态,这就说明还在循环中,因为SIGINT信号的处理函数不能更改quitflag的值,仍然不阻塞任何信号。
4、继续在另一终端上,执行 kill -s SIGQUIT pid程序结果如下:
please send signal: kill -s 3 4026
SIGINT
SIGQUIT
执行完后程序退出
5、为什么打印了“SIGQUIT\n”?不是被阻塞了么?原因是:sigsuspend不阻塞任何信号,所以呢,就执行了SIGQUIT的处理函数,改变了quitflag的值,quitflag = 1,打印"SIGQUIT\n"; 然后退出循环。紧接着sigsuspend恢复“原来的”信号掩码(这里的“原来的信号掩码”是包含阻塞SIGQUIT信号的),最后把信号掩码设置成最初的样子old_mask,程序退出。
情况三:
1、程序运行后,执行到sigsuspend函数,用空信号掩码zero_mask替换原来的信号掩码,即不阻塞任何信号。
2、开启另一终端,执行 kill -s SIGINT pid 程序结果如下:
please send signal: kill -s 3 4026
SIGINT
3、程序任在被挂起状态,这就说明还在循环中,因为SIGINT信号的处理函数不能更改quitflag的值,仍然不阻塞任何信号。
4、继续在另一终端上,执行 kill -s 40 pid程序结果如下:
please send signal: kill -s 3 4026
SIGINT
Real-time signal 5
执行完后程序退出
5、为什么打印了“Real-time signal 5\n”?原因是:sigsuspend不阻塞任何信号,所以呢,就执行了40的默认处理函数。那为什么退出了循环了?应该没改变quitflag的值啊?实际上,40信号的默认处理函数是打印一行字符后就直接终止程序了,所以后面的代码都没执行了。想要改变就必须重新注册40的处理函数。
#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>#include <errno.h>volatile sig_atomic_t quitflag; /* set nonzero by signal handler */void sig_int(int);intmain(int argc, char *argv[]) { sigset_t new_mask, old_mask, full_mask;struct sigaction act;quitflag = 0;sigemptyset(&act.sa_mask);act.sa_flags = 0;act.sa_handler = sig_int;if (sigaction(SIGINT, &act, NULL)) /* 注册信号SIGINT处理函数为sig_int */perror("sigaction(SIGINT) error\n");if (sigaction(SIGQUIT, &act, NULL)) /* 注册信号SIGQUIT处理函数为sig_int */ perror("sigaction(SIGQUIT) error\n");printf("please send signal (SIGINT): kill -s %d %d\n", SIGINT, getpid());printf("please send signal(SIGQUIT): kill -s %d %d\n", SIGQUIT, getpid());sigemptyset(&new_mask);sigaddset(&new_mask, SIGQUIT); /* 将信号SIGQUIT,添加到空信号集new_mask中 */if (sigprocmask(SIG_BLOCK, &new_mask, &old_mask)) /* 把信号SIGQUIT给阻塞 */perror("SIGQUIT error\n");sigfillset(&full_mask); /* 将所有信号添加到信号集full_mask */sigdelset(&full_mask, SIGQUIT); /* 将信号集full_mask中的SIGQUIT信号删除 *//* * 将当前的信号掩码替换成信号掩码full_mask (不包含SIGQUIT信号), * 也就是除了SIGQUIT信号其它信号都被阻塞,当前进程挂起。 * 只能等待SIGQUIT信号到来就可恢复成原来的信号掩码, * (这里“原来的信号掩码”是SIGQUIT信号被阻塞的信号集)。 * */while (quitflag == 0)sigsuspend(&full_mask);if (sigprocmask(SIG_SETMASK, &old_mask, NULL) < 0) /* 程序继续运行后恢复进程最初始的信号掩码 */perror("unblock signal error\n");exit(0);}void sig_int(int signum) {if (signum == SIGINT)printf("SIGINT\n");else if (signum == SIGQUIT) {printf("\nSIGQUIT\n");quitflag = 1;}}这里程序的情况分三种:
情况一:
1、程序运行后,执行到sigsuspend函数,用full_mask替换原来的信号掩码,除了SIGQUIT信号其它信号都被阻塞。
2、开启另一终端,执行 kill -s SIGINT pid 程序结果如下:
please send signal: kill -s 3 4026
3、程序任在被挂起状态,这就说明还在循环中,因为SIGINT信号被阻塞。
情况二:
1、程序运行后,执行到sigsuspend函数,用full_mask替换原来的信号掩码,除了SIGQUIT信号其它信号都被阻塞。
2、开启另一终端,执行 kill -s SIGINT pid 程序结果如下:
please send signal: kill -s 3 4026
3、程序任在被挂起状态,这就说明还在循环中,因为SIGINT信号被阻塞。
4、继续在另一终端上,执行 kill -s SIGQUIT pid程序结果如下:
please send signal: kill -s 3 4026
SIGQUIT
SIGINT
执行完后程序退出
5、为什么先打印了“SIGQUIT\n”?原因是:sigsuspend不阻塞SIGQUIT信号,所以呢,就执行了SIGQUIT的处理函数,改变了quitflag的值,quitflag = 1,打印"SIGQUIT\n"; 然后退出循环。紧接着sigsuspend恢复“原来的”信号掩码(这里的“原来的信号掩码”是阻塞SIGQUIT信号而不阻塞SIGINT的)所以接着打印“SIGINT\n”,最后把信号掩码设置成最初的样子old_mask,程序退出。
情况三:
1、程序运行后,执行到sigsuspend函数,用full_mask替换原来的信号掩码,除了SIGQUIT信号其它信号都被阻塞。
2、开启另一终端,执行 kill -s SIGINT pid 程序结果如下:
please send signal: kill -s 3 4026
3、程序任在被挂起状态,这就说明还在循环中,因为SIGINT信号被阻塞。
4、继续在另一终端上,执行 kill -s 40 pid程序结果如下(40信号也是被阻塞的,所以还在循环中):
please send signal: kill -s 3 4026
5、继续在另一终端上,执行 kill -s SIGQUIT pid程序结果如下:
please send signal: kill -s 3 4026
SIGQUIT
Real-time signal 5
执行完后程序退出
6、为什么没打印了“SIGINT\n”?原因是:实际上,40信号的默认处理函数是打印一行字符后就直接终止程序了,所以后面的代码都没执行了。想要改变就必须重新注册40的处理函数。(具体还没测试出来)
- apue2 第十章 信号:Unix/Linux信号阻塞(sigaction sigprocmask sigsuspend)
- Linux信号控制-sigprocmask,sigsuspend,sigpending,sigaction,sigqueue
- linux学习---信号(signal,sigaction,kill,sigqueue,sigprocmask,sigpending,sigsuspend)
- sigprocmask阻塞信号
- 信号:signal(), sigaction(), sigaddset(), sigemptyset(), sigismember(), sigprocmask()
- linux信号(sigprocmask,sigpending)
- linux 信号 sigsuspend abort
- linux信号 sigaction 进阶
- Linux signals(二) sigprocmask,sigaction,不可靠信号及实例代码
- C语言 linux信号和阻塞 sigaction…
- 信号基本操作之sigprocmask阻塞进程
- UNIX环境高级编程学习之第十章信号-信号集的操作,让进程阻塞SIGQUIT信号
- linux信号--阻塞信号
- Linux sigaction信号机制积累
- LINUX信号- sigaction 函数-10.14
- 信号相关函数(signal,sigaction,sigprocmask, kill,sigqueue信号发送函数,睡眠函数,计时器函数)
- Linux下信号--阻塞信号
- 《Unix高级环境编程》第十章 信号
- Get Your Database Under Version Control
- Java多线程设计模式详解学习笔记九——Thread-Per-Message
- linux下安装tftp--问题多多
- android中adb shell常用命令及查询数据库的方法
- c语言的三个小程序
- apue2 第十章 信号:Unix/Linux信号阻塞(sigaction sigprocmask sigsuspend)
- [Android]异步任务AsyncTask使用解析
- Visual Studio调试技巧
- 针对Lobby Server卡死后补偿CashOut数据的脚本
- exchange命令行管理工具"常用操作命令
- 什么是序列化?
- 普通GPIO口线模拟I2C
- 推荐10个开发者最常用的代码编辑器
- 请教 ANDROID 通信信号、网络信号图标的颜色问题