Linux入门:信号(二)——阻塞信号

xiaoxiao2021-02-28  263

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

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

       进程可以选择阻塞(Block)某个信号。被阻塞的信号产生时将保持在未决状态,直到进程接触对此信号的阻塞,才执行递达的操作。(阻塞和忽略不同,只有信号阻塞就不会递达,而忽略是在信号递达之后可选的一种处理动作。而一个被阻塞的信号想要递达,需要先Pending再解除阻塞。)

       每个信号都有两个标志位分别表示阻塞和未决,还有一个函数指针表示处理动作。信号产生时,内核在进程的PCB设置该信号的未决标志,直到信号递达才清除该标志。

      如果进程在解除对某信号的阻塞之前这种信号产生了多次,将如何处理?POSIX.1允许系统递达信号一次或多次。在Linux中:常规信号在递达之前产生多次只计一次,实时信号在递达之前产生多次可以依次放在一个队列里。对于常规信号,每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集。

信号的阻塞就是让系统暂时保留信号待以后发送。由于另外有办法让系统忽略信号,所以一般情况下信号的阻塞只是暂时的,只是为了防止信号打断敏感的操作。当需要修改某些全局变量时,可以通过sigprocmask()函数阻塞处理函数中也使用该变量的信号。在某些信号处理函数中,为了防止同类信号的到来,可以使用sigaction()函数的sa_mask阻塞特定的信号。

    阻塞信号的作用:使用函数sigprocmask()阻塞信号的传递,只是延迟信号的到达。信号会在解除阻塞后继续传递。这种情况往往需要在信号程序和其它程序共享全局变量时,如果全局变量的类型不是sig_atomic_t类型,当一部分程序恰好读、写到变量过程中,产生某个信号,而信号程序里会改变该变量,那么就会产生混乱。为了避免这种混乱,提供程序的可靠性,你必须在操作这类变量前阻塞信号,操作完成后恢复信号的传递。

信号集操作函数: 程序: #include <stdio.h> #include <signal.h> void handler(int sig) { printf("sig = %d\n", sig); } void show_pending(sigset_t *pending) { int i = 1; for(i=1; i<=31; i++) { //判断指定信号是否在目标信号集中 if(sigismember(pending, i)) { printf("1"); } else { printf("0"); } } printf("\n"); } int main() { //捕捉2号信号 signal(2, handler); sigset_t block; sigset_t oldblock; sigset_t pending; sigemptyset(&block); sigemptyset(&oldblock); //设置阻塞信号集,阻塞2号信号 sigaddset(&block, 2); sigprocmask(SIG_SETMASK, &block, &oldblock); int count = 0; while(1) { //获取未决信号集 sigpending(&pending); show_pending(&pending); sleep(1); count++; if(count == 10) { //解除对当前未决信号的阻塞 sigprocmask(SIG_SETMASK, &oldblock, NULL); } } return 0; } 运行结果: 程序运行时,每秒钟把各信号的未决状态打印一遍,由于我们阻塞了SIGINT信号,则使SIGINT信号(Ctrl-C)处于未决状态,按Ctrl-Z则可以终止程序.

转载请注明原文地址: https://www.6miu.com/read-79571.html

最新回复(0)