Linux系统编程49 信号 - sigprocmask() 设置信号集当中信号的mask信号屏蔽字

sigprocmask() :虽然我不知道信号什么时候来,但是我可以决定 什么时候响应信号

信号集:

NAME
sigemptyset, sigfillset, sigaddset, sigdelset, sigismember - POSIX signal set operations

SYNOPSIS
#include <signal.h>

int sigemptyset(sigset_t *set); 清空信号集

int sigfillset(sigset_t *set); 填充满 信号集

int sigaddset(sigset_t *set, int signum); 向信号集中添加信号

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

int sigismember(const sigset_t *set, int signum); 判断 信号是否存在于指定集合中
1
2
3
4
5
6
7
8
9
信号机类型:sigset_t

信号屏蔽字处理

sigprocmask(); // 控制 信号相应过程中的 mask位图,mask 位图 用来标记是否响应各个信号,1为响应 0为忽略

NAME
sigprocmask, rt_sigprocmask - examine and change blocked signals

SYNOPSIS
#include <signal.h>

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
1
2
3
4
5
6
7
对 set信号集中的所有信号 作 how 动作操作,oldset保留的是 对该信号集操作之前的 信号集中信号的状态

The behavior of the call is dependent on the value of how, as follows.

SIG_BLOCK 对目标信号集中的所有信号进行阻塞,即将mask信号屏蔽位置0
The set of blocked signals is the union of the current set and the set argument.

SIG_UNBLOCK 对目标信号集中的所有信号解除阻塞 即将mask信号屏蔽位置1
The signals in set are removed from the current set of blocked signals. It is permissible to attempt to unblock a signal which is not blocked.

SIG_SETMASK 回复信号集之前的状态,并保存信号集恢复之前的当前状态
The set of blocked signals is set to the argument set.

RETURN VALUE 0为成功,-1为失败
sigprocmask() returns 0 on success and -1 on error. In the event of an error, errno is set to indicate the cause.
1
2
3
4
5
6
7
8
9
10
11
12
13
实验:
每秒向标准输出打印一个* 打印五秒换行。程序不受 CTRL+C 即 SIGINT信号影响,收到 SIGINT信号 响应信号 打印!。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void sig_handler(int s)
{
write(1,"!",1);
}

int main()
{
int i,j;

signal(SIGINT,sig_handler);
for(j=0;j < 1000;j++)
{

for(i=0 ; i<5 ; i++)
{
write(1,"*",1);
sleep(1);
}
write(1,"\n",1);
}


exit(0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
修改: sigprocmask(SIG_BLOCK…)+ sigprocmask(SIG_UNBLOCK…)
只在两行*之间输出 !, 即 选择响应 SIGINT 信号的时间。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


void sig_handler(int s)
{
write(1,"!",1);
}

int main()
{
int i,j;
sigset_t set;//创建信号集

signal(SIGINT,sig_handler);

sigemptyset(&set); //清空信号集
sigaddset(&set,SIGINT); // 添加 SIGINT信号 到信号集


for(j=0;j < 1000;j++)
{

sigprocmask(SIG_BLOCK,&set,NULL); // 对 set信号集中的信号 进行阻塞,即将mask信号屏蔽位置0
for(i=0 ; i<5 ; i++)
{
write(1,"*",1);
sleep(1);
}
write(1,"\n",1);
sigprocmask(SIG_UNBLOCK,&set,NULL); // 对 set信号集中的信号 解除阻塞,即将mask信号屏蔽位置1
}


exit(0);
}


mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$ gcc sigprocmask.c
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$ ./a.out
***^C*^C*^C^C^C^C^C
!*^C^C^C^C^C^C*^C^C^C^C^C^C*^C**
!*****
*^C*^C^C^C^C^C*^C^C*^C*
!*****
*****
*****
*****
*****
****^C*^C
!***^C^C**
!*****^\Quit (core dumped)
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
注意:两次sigprocmask之间

sigprocmask(SIG_BLOCK,&set,NULL);

注意1
这之间 已经屏蔽了 SIGINT 信号,即将SIGINT 的mask信号屏蔽位置0,所以就算有信号来,mask信号屏蔽位 按位与 pending信号状态位,结果也是0,所以不响应 SIGINT信号的动作,即不打印!

注意2
只有解除 SIGINT 信号阻塞,即将mask信号屏蔽位置1,并赶上 程序从内核态切换回用户态的时候 才会计算mask信号屏蔽位 按位与 pending信号状态位 的结果,并响应SIGINT 信号动作,即 打印!

注意3
而且 不论 发送多少个 SIGINT 信号,只会打印一个 !,即只会响应一次信号。这就是之前 在 信号的响应过程 中说的 标准信号为什么要丢失 这个问题了,信号的响应过程那篇文章很关键,信号的响应过程那篇文章很关键,信号的响应过程那篇文章很关键,信号的响应过程那篇文章很关键,信号的响应过程那篇文章很关键


sigprocmask(SIG_UNBLOCK,&set,NULL);

并且 还有一点很重要,发现实验中 SIGINT 信号 也不会打断阻塞的系统调用了。只有 SIG_BLOCK 之后才会,原因同上,因为已经屏蔽了该信号。

修改: sigprocmask(SIG_BLOCK…)+ sigprocmask(SIG_SETMASK …)

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


void sig_handler(int s)
{
write(1,"!",1);
}

int main()
{
int i,j;
sigset_t set,oset;//创建信号集

signal(SIGINT,sig_handler);

sigemptyset(&set); //清空信号集
sigaddset(&set,SIGINT); // 添加 SIGINT信号 到信号集


for(j=0;j < 1000;j++)
{

// 对 set信号集中的信号 进行阻塞,即将mask信号屏蔽位置0. 并且将 信号集阻塞之前的状态保存到 oset
sigprocmask(SIG_BLOCK,&set,&oset);
for(i=0 ; i<5 ; i++)
{
write(1,"*",1);
sleep(1);
}
write(1,"\n",1);

//即 恢复 oset信号集,即解除阻塞
sigprocmask(SIG_SETMASK,&oset,NULL);
}


exit(0);
}


mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$ gcc sigprocmask.c
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$ ./a.out
***^C*^C*^C^C^C^C^C
!*^C^C^C^C^C^C*^C^C^C^C^C^C*^C**
!*****
*^C*^C^C^C^C^C*^C^C*^C*
!*****
*****
*****
*****
*****
****^C*^C
!***^C^C**
!*****^\Quit (core dumped)
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/signal/test$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
结果一样

通常的做法是:一定要保存和回复 修改之前的信号集状态

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


void sig_handler(int s)
{
write(1,"!",1);
}

int main()
{
int i,j;
sigset_t set,saveset;//创建信号集

signal(SIGINT,sig_handler);

sigemptyset(&set); //清空信号集
sigaddset(&set,SIGINT); // 添加 SIGINT信号 到信号集

//在当前模块修改之前 保存信号集状态,以便 当前模块执行完成后恢复 信号集状态
sigprocmask(SIG_UNBLOCK,&set,&saveset);

for(j=0;j < 1000;j++)
{

sigprocmask(SIG_BLOCK,&set,NULL); // 对 set信号集中的信号 进行阻塞,即将mask信号屏蔽位置0
for(i=0 ; i<5 ; i++)
{
write(1,"*",1);
sleep(1);
}
write(1,"\n",1);
sigprocmask(SIG_UNBLOCK,&set,NULL); // 对 set信号集中的信号 解除阻塞,即将mask信号屏蔽位置1
}

// 恢复 之前信号集状态
sigprocmask(SIG_SETMASK,&saveset,NULL);

exit(0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/LinuxArmbiggod/article/details/114114857

 

posted @ 2024-02-02 10:17  imxiangzi  阅读(31)  评论(0编辑  收藏  举报