linux信号屏蔽字
来源:互联网 发布:为什么动物会怕死知乎 编辑:程序博客网 时间:2024/04/24 20:47
一个进程的信号屏蔽字规定了当前阻塞而不能递送给该进程的信号集。调用函数sigprocmask可以检测或更改其信号屏蔽字,或者在一个步骤中同时执行这两个操作。
#include <signal.h>int sigprocmask( int how, const sigset_t *restrict set, sigset_t *restrict oset );返回值:若成功则返回0,若出错则返回-1
首先,若oset是非空指针,那么进程的当前信号屏蔽字通过oset返回。
其次,若set是一个非空指针,则参数how指示如何修改当前信号屏蔽字。
表10-4说明了how可选用的值。注意,不能阻塞SIGKILL和SIGSTOP信号。
表10-4 用sigprocmask更改当前信号屏蔽字的方法
how
说明
SIG_BLOCK 该进程新的信号屏蔽字是其当前信号屏蔽字和set指向信号集的并集。set包含了我们希望阻塞的附加信号 SIG_UNBLOCK 该进程新的信号屏蔽字是其当前信号屏蔽字和set所指向信号集补集的交集。set包含了我希望解除阻塞的信号 SIG_SETMASK 该进程新的信号屏蔽字将被set指向的信号集的值代替
如果set是空指针,则不改变该进程的信号屏蔽字,how的值也无意义。
在调用sigprocmask后如果有任何未决的、不再阻塞的信号,则在sigprocmask返回前,至少会将其中一个信号递送给该进程。
1、有时候不希望在接到信号时就立即停止当前执行,去处理信号,同时也不希望忽略该信号,而是延时一段时间去调用信号处理函数。这种情况是通过阻塞信号实现的。
2、信号阻塞和忽略信号的区别。
阻塞的概念和忽略信号是不同的。操作系统在信号被进程解除阻塞之前不会讲信号传递出去,被阻塞的信号也不会影响进程的行为,信号只是暂时被阻止传递。当进程忽略一个信号时,信号会被传递出去但进程会将信号丢弃。
1)头文件:#include <signal.h>
2)一个保护临界区代码的错误实例:(sigprocmask()和pause()实现)
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void handler(intsig)
{
}
int main()
{
}
上面实例的问题是:本来期望pause()之后,来SIGINT信号,可以结束程序;可是,如果当“取消阻塞”和“pause”之间,正好来了SIGINT信号,结果程序因为pause的原因会一直挂起。。。
解决的方式,当然是sigsuspend()函数了。
3)使用sigsuspend()的程序
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void handler(int sig)
{
}
int main()
{
}
sigsuspend的原子操作是:
(1)设置新的mask阻塞当前进程(上面是用wait替换new,即阻塞SIGUSR1信号)
(2)收到SIGUSR1信号,阻塞,程序继续挂起;收到其他信号,恢复原先的mask(即包含SIGINT信号的)。
(3)调用该进程设置的信号处理函数(程序中如果先来SIGUSR1信号,然后过来SIGINT信号,则信号处理函数会调用两次,打印不同的内容。第一次打印SIGINT,第二次打印SIGUSR1,因为SIGUSR1是前面阻塞的)
(4)待信号处理函数返回,sigsuspend返回了。(sigsuspend将捕捉信号和信号处理函数集成到一起了)
总结:
在nginx源码中,ngx_master_process_cycle函数中,首先调用了sigprocmask()函数阻塞了部分信号,在for循环中调用了sigsuspend函数 ,但是sigsuspend函数中的set为空,也就是说,在for循环之前,如果有set集合中的信号到来就阻塞,在for循环之内,任何信号到来都进程处理。函数返回之后同时也恢复了原来的信号掩码!
sigsuspend的整个原子操作过程为:
(1) 设置新的mask阻塞当前进程;
(2) 收到信号,恢复原先mask;
(3) 调用该进程设置的信号处理函数;
(4) 待信号处理函数返回后,sigsuspend返回。
大致就是上面这个过程,噢,原来signal handler是原子操作的一部分,而且是在恢复屏蔽字后执行的,
int sigsuspend(const sigset_t *sigmask);
此函数用于进程的挂起,sigmask指向一个信号集。当此函数被调用时,sigmask所指向的信号集中的信号将赋值给信号掩码。之后进程挂起。直到进程捕捉到信号,并调用处理函数返回时,函数sigsuspend返回。信号掩码恢复为信号调用前的值,同时将errno设为EINTR。进程结束信号可将其立即停止。
- #include <stdio.h>
- #include <signal.h>
- void checkset();
- void func();
- void main()
- {
- sigset_tblockset,oldblockset,zeroset,pendmask;
- printf("pid:%ld\n",(long)getpid());
- signal(SIGINT,func);
- sigemptyset(&blockset);
- sigemptyset(&zeroset);
- sigaddset(&blockset,SIGINT);
- sigprocmask(SIG_SETMASK,&blockset,&oldblockset);
- checkset();
- sigpending(&pendmask);
- if(sigismember(&pendmask,SIGINT))
- printf("SIGINTpending\n");
- //不阻塞任何信号 任何信号到来都会激活进程
- if(sigsuspend(&zeroset)!= -1)
- {
- printf("sigsuspenderror\n");
- exit(0);
- }
- printf("afterreturn\n");
- sigprocmask(SIG_SETMASK,&oldblockset,NULL);
- printf("SIGINTunblocked\n");
- }
- void checkset()
- { sigset_tset;
- printf("checksetstart:\n");
- if(sigprocmask(0,NULL,&set)<0)
- {
- printf("checksetsigprocmask error!!\n");
- exit(0);
- }
- if(sigismember(&set,SIGINT))
- printf("sigint\n");
- if(sigismember(&set,SIGTSTP))
- printf("sigtstp\n");
- if(sigismember(&set,SIGTERM))
- printf("sigterm\n");
- printf("checksetend\n");
- }
- void func()
- {
- printf("hellofunc\n");
- }
- pid:5474
- checksetstart:
- sigint
- checksetend
- ^Chellofunc
- afterreturn
- checksetstart:
- checksetend
- SIGINTunblocked
从运行的结果 以及和上面的例子进行比较较就可以知道这两个函数的函数。
- linux信号屏蔽字
- linux信号集与信号屏蔽字
- Linux Signal (6): 信号屏蔽字
- Linux Signal (6): 信号屏蔽字
- Linux Signal (6): 信号屏蔽字
- Linux Signal (5): 信号屏蔽字
- linux 信号屏蔽
- Linux--信号屏蔽
- linux信号屏蔽
- 信号屏蔽字
- 信号屏蔽字
- 信号屏蔽字
- linux进程中的信号屏蔽
- linux之信号屏蔽pending
- Linux中如何屏蔽信号
- Linux c 屏蔽信号、切换信号
- Linux c之 信号屏蔽字sigprocmask()
- 信号屏蔽字&信号未决字
- 你是不是想得太简单了
- 两人生日相同的概率
- 开发单页应用(SPA)时候遇到的微信支付授权目录的坑
- 关于NGUI置灰的方案
- bestcoder 1002 列变位法解密(模拟)
- linux信号屏蔽字
- Animate.css 基础使用方法
- 【IIS】ISS安装及网站的发布
- set容器中放入结构体时需要重载运算符<
- hive union 的问题
- A - Rooks
- c++中反斜杠(\)的不常用的用法
- GOT S06E03
- 上海房租又涨了