赞
踩
目录
在Linux中,常用的信号有31个,内核中则存在一个类似于位图的方式来对该进程的block,peding进行表示,由于不存在0号信号,所以信号就从1号位置开始到31,如果该位置上为1则表示该信号当前存在,为0则表示不存在。
- #include <signal.h>
- int sigemptyset(sigset_t *set);
- int sigfillset(sigset_t *set);
- int sigaddset (sigset_t *set, int signo);
- int sigdelset(sigset_t *set, int signo);
- int sigismember(const sigset_t *set, int signo);
- #include <signal.h>
- int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
- 返回值:若成功则为0,若出错则为-1
- #include <signal.h>
-
- sigset_t pendig;
- int n=sigpending(&pending);
- 读取当前进程的未决信号集,通过set参数传出。调用成功则返回0则n=0,出错则返回-1则n=-1。
清空sigset_t类型内部的数据。
- sigset_t pending;
- sigemptyset(&pending);
- 考虑到各个平台的不同,这种方式可以很好解决在栈上生成随机值的情况
- #include <iostream>
- #include <signal.h>
- #include <unistd.h>
- #include <cassert>
- #include <sys/wait.h>
-
- void PrintSig(sigset_t &pending)
- {
- std::cout << "Pending bitmap: ";
- for (int signo = 31; signo > 0; signo--)
- {
- if (sigismember(&pending, signo))//判断该信号是否在信号集中
- {
- std::cout << "1";
- }
- else
- {
- std::cout << "0";
- }
- }
- std::cout << std::endl;
- }
-
- void handler(int signo)
- {
- sigset_t pending;
- sigemptyset(&pending);
- int n = sigpending(&pending); // 正在处理2号信号
- assert(n == 0);
-
- // 3. 打印pending位图中的收到的信号
- std::cout << "递达中...: ";
- PrintSig(pending); // 0: 递达之前,pending 2号已经被清0. 1: pending 2号被清0一定是递达之后
- std::cout << signo << " 号信号被递达处理..." << std::endl;
- }
-
- int main()
- {
- // 对2号信号进行自定义捕捉 --- 不让进程因为2号信号而终止
- signal(2, handler);
-
- // 1. 屏蔽2号信号
- sigset_t block, oblock;
- sigemptyset(&block);
- sigemptyset(&oblock);
- sigaddset(&block, 2); // SIGINT --- 根本就没有设置进当前进程的PCB block位图中
-
- // 0. for test: 如果我屏蔽了所有信号呢???
- // for(int signo = 1; signo <= 31; signo++) // 9, 19号信号无法被屏蔽, 18号信号会被做特殊处理
- // sigaddset(&block, signo); // SIGINT --- 根本就没有设置进当前进程的PCB block位图中
- // 1.1 开始屏蔽2号信号,其实就是设置进入内核中
- int n = sigprocmask(SIG_SETMASK, &block, &oblock);
- assert(n == 0);
- // (void)n; // 骗过编译器,不要告警,因为我们后面用了n,不光光是定义
- std::cout << "block 2 signal success" << std::endl;
- std::cout << "pid: " << getpid() << std::endl;
- int cnt = 0;
- while (true)
- {
- // 2. 获取进程的pending位图
- sigset_t pending;
- sigemptyset(&pending);
- n = sigpending(&pending);
- assert(n == 0);
-
- // 3. 打印pending位图中的收到的信号
- PrintSig(pending);
- cnt++;
-
- // 4. 解除对2号信号的屏蔽
- if (cnt == 20)
- {
- std::cout << "解除对2号信号的屏蔽" << std::endl;
- n = sigprocmask(SIG_UNBLOCK, &block, &oblock); // 2号信号会被立即递达, 默认处理是终止进程
- assert(n == 0);
- }
- // 我还想看到pending 2号信号 1->0 : 递达二号信号!
- sleep(1);
- }
-
- return 0;
- }
通过以上代码所演示的现象我们也可以验证两个结论:
1、递达信号的时候一定会把对应的pending位图清0。
2、先清0,再递达。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。