本文接上篇文章:http://www.tgwttt.xyz/?p=271

保存信号

信号其他相关常⻅概念

• 实际执⾏信号的处理动作称为信号递达(Delivery)

• 信号从产⽣到递达之间的状态,称为信号未决(Pending)。

• 进程可以选择阻塞 (Block )某个信号。

• 被阻塞的信号产⽣时将保持在未决状态,直到进程解除对此信号的阻塞,才执⾏递达的动作.

• 阻塞和忽略是不同的,只要信号被阻塞就不会递达,⽽忽略是在递达之后可选的⼀种处理动作。

信号在内核中的表⽰⽰意图

每个信号都有两个标志位分别表⽰阻塞(block)和未决(pending),还有⼀个函数指针表⽰处理动作。信号产⽣时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。在上图的例⼦中,SIGHUP信号未阻塞也未产⽣过,当它递达时执⾏默认处理动作。

• SIGINT信号产⽣过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。

• SIGQUIT信号未产⽣过,⼀旦产⽣SIGQUIT信号将被阻塞,它的处理动作是⽤⼾⾃定义函数sighandler。 如果在进程解除对某信号的阻塞之前这种信号产⽣过多次,将如何处理?POSIX.1允许系统递送该信号⼀次或多次。Linux是这样实现的:常规信号在递达之前产⽣多次只计⼀次,⽽实时信号在递达之前产⽣多次可以依次放在⼀个队列⾥。

sigset_t
每个信号只有⼀个bit的未决标志, ⾮0即1, 不记录该信号产⽣了多少次,阻塞标志也是这样表⽰的。因此, 未决和阻塞标志可以⽤相同的数据类型sigset_t来存储, , 这个类型可以表⽰每个信号的“有效”或“⽆效”状态, 在阻塞信号集中“有效”和“⽆效”的含义是该信号是否被阻塞, ⽽在未决信号集中“有 效”和“⽆效”的含义是该信号是否处于未决状态。阻塞信号集也叫做当前进程的 这⾥的“屏蔽”应该理解为阻塞⽽不是忽略。

信号集操作函数
#i nclude

int sigemptyset(sigset_t *set);将信号集 set 清空,即不包含任何信号。

int sigfillset(sigset_t *set); 将信号集 set 填满,即包含所有可能的信号。

int sigaddset(sigset_t *set, int signo); 将信号 signo 添加到信号集 set

int sigdelset(sigset_t *set, int signo);将信号 signo 从信号集 set 中删除

int sigismember(const sigset_t *set, int signo);判断信号 signo 是否在信号集 set 中。

sigprocmask

#include 
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);

如果oset是⾮空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是⾮空指针,则 更改进程的信 号屏蔽字,参数how指⽰如何更改。如果oset和set都是⾮空指针,则先将原来的信号 屏蔽字备份到oset⾥,然后 根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。

sigpending

#include

int sigpending(sigset_t *set);

读取当前进程的未决信号集,通过set参数传出。调⽤成功则返回0,出错则返回-1

代码举例:

int main(){
// 0. 捕捉2号信号
signal(2, handler); // ⾃定义捕捉//signal(2, SIG_IGN); // 忽略⼀个信号//signal(2, SIG_DFL); // 信号的默认处理动作
// 1. 屏蔽2号信号
sigset_t block_set, old_set;sigemptyset(&block_set);
sigemptyset(&old_set);
sigaddset(&block_set, SIGINT); 
sigprocmask(SIG_BLOCK, &block_set, &old_set); // 真正的修改当前进⾏的内核block表,完成了对2号信号的屏蔽!
int cnt = 15;while (true){
// 2. 获取当前进程的pending信号集
sigset_t pending;sigpending(&pending);
// 3. 打印pending信号集
PrintPending(pending);cnt--;
// 4. 解除对2号信号的屏蔽
if (cnt == 0){
std::cout << "解除对2号信号的屏蔽!!!" << std::endl;sigprocmask(SIG_SETMASK, &old_set, &block_set);
} 
sleep(1);
}

当被屏蔽后会一直打印curr process[448336]pending: 0000000000000000000000000000010

捕捉信号

捕捉信号流程示意图:

sigaction

#include int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);

今天的博客就写到这里,如有错误欢迎指出!!