【linux编程】信号集、sigprocmask、sigpending

 信号集、sigprocmask、sigpending

信号源为目标进程产生了一个信号,然后由内核来决定是否要将该信号传递给目标进程。从信号产生到传递给目标进程的流程图如下图所示:

 

进程可以阻塞信号的传递。当信号源为目标进程产生了一个信号之后,内核会执行依次执行下面操作,

1. 如果目标进程设置了忽略该信号,则内核直接将该信号丢弃。

2. 如果目标进程没有阻塞该信号,则内核将该信号传递给目标进程,由目标进程执行相对应操作。

3. 如果目标进程设置阻塞该信号,则内核将该信号放到目标进程的阻塞信号列表中,等待目标进程对该类型信号的下一步设置。若目标进程后续设置忽略该信号,则内核将该信号从目标进程的阻塞信号列表中移除并丢弃。若目标进程对该信号解除了阻塞,内核将该信号传递给目标进程进行相对应的操作。

在信号产生到信号传递给目标进程之间的时间间隔内,我们称该信号为未决的(pending)。

每个进程都有一个信号屏蔽字(signal mask),它规定了当前要阻塞传递给该进程的信号集。对于每种可能的信号,信号屏蔽字中都有一位与之对应。

 

 1. 信号集:

sigset_t set;                                     //typedef unsigned long sigset_t
int sigemptyset(sigset_t *set)                    // 将某个信号集清0
int sigfillset(sigset_t *set)                     // 将某个信号集置1
int sigaddsetset(sigset_t *set, int sino)         // 将某个信号加入信号集
int sigdelset(sigset_t *set, int signo)           // 将某个信号清出信号集

 

 

 2. 函数sigprocmask

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

 

分析:

1. set:传入参数,是一个位图,set中哪个位置置为1,就表示当前进程屏蔽了哪个信号

2. oldset:传出参数,保存旧的信号屏蔽集

3. how参数取值

  • SIG_BLOCK:当how设置为此值,set表示需要屏蔽的信号
  • SIGB_UNBLOCK:当how设置为此值,set表示需要解除屏蔽的信号
  • SIG_SETMASK:当how设置为此值,set表示用于替代原始屏蔽集的新屏蔽集,相当于mask = set,若调用sigprocmask解除了对当前信号若干个信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达。

 

3. 函数sigpendin:读取当前信号的未决信号集

int sigpending(sigset_t *set);     //set传出参数

 

1. 测试代码

 1 #include <stdio.h>
 2 #include <signal.h>
 3 #include <unistd.h>
 4  
 5 void printped(sigset_t *ped)
 6 {
 7     int i;
 8     for (i = 1; i < 32; i++) 
 9     {
10         if (sigismember(ped, i) == 1) 
11             putchar('1');
12         else 
13             putchar('0');
14     }
15     printf("\n");
16 }
17  
18 int main()
19 {
20     sigset_t myset, oldset, ped;
21     sigemptyset(&myset);
22     sigaddset(&myset, SIGQUIT); // Ctrl + /
23     sigaddset(&myset, SIGINT);  // Ctrl + C
24     sigaddset(&myset, SIGTSTP); // Ctrl + Z
25     sigaddset(&myset, SIGSEGV);
26     sigaddset(&myset, SIGKILL);  //无法被屏蔽
27     sigprocmask(SIG_BLOCK, &myset, &oldset);
28     while (1) 
29     {
30         sigpending(&ped);
31         printped(&ped);
32         sleep(2);
33     }
34     return 0;
35 }

 输出结果:

 

2. 测试代码:

 1 #include <unistd.h> 
 2 #include <signal.h>
 3 #include <string.h>
 4 #include <stdio.h>
 5 #include <stdlib.h>
 6  
 7 void handler(int sig)
 8 {
 9     if (sig == SIGINT)
10         printf("recv a sig = %d\n", sig);
11     else if (sig == SIGQUIT) 
12     {
13         sigset_t uset;
14         sigemptyset(&uset);
15         sigaddset(&uset, SIGINT);
16         sigprocmask(SIG_UNBLOCK, &uset, NULL);
17     }
18 }
19  
20 void printsigset(sigset_t *set)
21 {
22     int i;
23     for (i = 1; i < 32; ++i)
24     {
25         if (sigismember(set, i))
26             putchar('1');
27         else             
28             putchar('0');
29     }
30     printf("\n");
31 }
32  
33 int main(int argc, char *argv[])
34 {
35     sigset_t pset;
36     sigset_t bset;
37     sigemptyset(&bset);
38     sigaddset(&bset, SIGINT);
39     if (signal(SIGINT, handler) == SIG_ERR) 
40     {
41         perror("signal error");
42         exit(1);
43     }
44     if (signal(SIGQUIT, handler) == SIG_ERR) 
45     {
46         perror("signal error");
47         exit(1);
48     }
49     sigprocmask(SIG_BLOCK, &bset, NULL);
50     for (; ;)
51     {
52         sigpending(&pset);
53         printsigset(&pset);
54         sleep(1);
55     }
56     return 0;
57 }

 输出结果:

 

参考资料

1. linux c编程:信号(三) sigprocmask和sigpending函数

posted @ 2019-01-11 21:22  苏格拉底的落泪  阅读(326)  评论(0)    收藏  举报