信号集与屏蔽字
来源:互联网 发布:淘宝号怎么有心 编辑:程序博客网 时间:2024/04/30 06:48
1.信号集和信号集处理函数
信号集是一个位向量,其中每一位对应着linux系统的一个信号。可使用如下函数对信号集进行处理:
1
#include <signal.h>
2
3
int
sigemptyset(sigset_t * set);
4
5
int
sigfillset(sigset_t * set);
6
7
int
sigaddset(sigset_t * set);
8
9
int
sigdelset(sigset_t * set);
sigemptyset将一个信号集清空;sigfillset将信号集的所有位置位;sigaddset函数将参数signo指定的信号所对应的位设置为1;sigdelset将signo的对应位设置为0。
使用如下函数检测信号集的相应位是否被设置:
1
#include <signal.h>
2
3
int
sigismember(sigset_t * set,
int
aigno);
返回值为1时,代表该位被设置,返回值为0时,代表该位未被设置,失败则返回-1。
//sigset.c 使用信号集处理函数测试并设置相应信号的位
01
#include <stdio.h>
02
03
#include <signal.h>
04
05
int
main()
06
07
{
08
09
sigset_t sig_set;
10
11
sigemptyset(&sig_set);
//清空信号集
12
13
sigaddset(&sig_set,SIGKILL-1);
//设置SIGKILL的相应位
14
15
if
(sigismember(&sig_set,SIGKILL))==1){
16
17
printf
(
"SIGKILL has been set/n"
);
18
19
else
20
21
printf
(
"can't set signal set/n"
);
22
23
return
0;
24
25
}
2.屏蔽信号
阻塞一些信号,使进程即使接收到信号,也不做处理。
使用如下函数:
1
#include <signal.h>
2
3
int
sigprocmask(
int
how,
const
sigset_t *set,sigset_t *oldset);
函数说明 sigprocmask()可以用来改变目前的信号屏蔽,其操作依参数how来决定
SIG_BLOCK 新的信号屏蔽由目前的信号屏蔽和参数set 指定的信号屏蔽作联集
SIG_UNBLOCK 将目前的信号屏蔽删除掉参数set指定的信号屏蔽
SIG_SETMASK 将目前的信号屏蔽设成参数set指定的信号屏蔽。
如果参数oldset不是NULL指针,那么目前的信号屏蔽会由此指针返回。
返回值 执行成功则返回0,如果有错误则返回-1。
错误代码 EFAULT 参数set,oldset指针地址无法存取。
EINTR 此调用被中断
如果set的值为NULL,则无论how是何值都不会更改信号屏蔽字。这种方法用于得到当前进程的信号屏蔽字。
sigprocmask(0,NULL,&oset);
01
#include <stdio.h>
02
#include <stdlib.h>
03
#include <signal.h>
04
05
void
sigusr1_handler(
int
signo)
06
{
07
printf
(
"catch SIGUSR1/n"
);
08
}
09
10
int
main(
void
)
11
{
12
sigset_t set;
13
14
if
(
signal
(SIGUSR1, sigusr1_handler) == SIG_ERR){
15
perror
(
"can¡¯t set handler for SIGUSR1"
);
16
exit
(1);
17
}
18
19
sigemptyset(&set);
//清空信号集
20
sigaddset(&set, SIGUSR1 - 1);
//设置SIGUSR1
21
22
if
(sigprocmask(SIG_BLOCK, &set, NULL) == -1){
//屏蔽该信号
23
perror
(
"fail to set signal-mask"
);
24
exit
(1);
25
}
26
27
printf
(
"SIGUSR1 is not available/n"
);
28
29
sleep(10);
//休眠,等待用户发送SIGUSR1信号
30
31
if
(sigprocmask(SIG_UNBLOCK, &set, NULL) == -1){
//恢复屏蔽的信号
32
perror
(
"fail to set signal-mask"
);
33
exit
(1);
34
}
35
36
printf
(
"SIGUSR1 is available now/n"
);
37
38
sleep(10);
//休眠,等待用户发送SIGUSR1信号
39
40
return
0;
41
}
3.处理未决信号
如果屏蔽了一个信号,但是进程还是从某处接收到了此信号,这种信号叫做未决的。这种信号是悬而未决的。
如果调用sigprocmask后有任何未决的但是已经不再阻塞的信号时,在该函数返回之前,至少会将这些解放了的未决信号中的一个发送给该进程。linux中使用sigpending函数检查未决信号,其函数的原型如下;
1
#include <signal.h>
2
3
int
sigpending(sigset_t * set);
set表示当前进程中所有未决的信号。如果成功得到未决信号集,返回0,否则返回-1。
下例先阻塞SIGUSR1信号,之后向该进程发送SIGUSR1信号,此信号为未决的,使用sigpending函数测试是否有一个未决的SIGUSR1信号,最后取消对该信号的阻塞,处理这个信号。
01
#include <stdio.h>
02
#include <stdlib.h>
03
#include <signal.h>
04
05
void
sigusr1_handler(
int
signo)
06
{
07
printf
(
"catch SIGUSR1/n"
);
08
}
09
10
int
main(
void
)
11
{
12
sigset_t set;
13
sigset_t sig_pend;
14
15
sigemptyset(&set);
16
sigemptyset(&sig_pend);
17
18
if
(
signal
(SIGUSR1, sigusr1_handler) == SIG_ERR){
19
perror
(
"can¡¯t set handler for SIGUSR1"
);
20
exit
(1);
21
}
22
23
sigaddset(&set, SIGUSR1 - 1);
//添加SIGUSR1信号
24
25
if
(sigprocmask(SIG_BLOCK, &set, NULL) == -1){
//阻塞SIGUSR1
26
perror
(
"fail to set signal-mask"
);
27
exit
(1);
28
}
29
30
sleep(10);
//休眠10,期间接收信号,注意进程休眠后不会被未决的信号唤醒
31
32
if
(sigpending(&sig_pend) == -1){
//得到所有的未决信号集
33
perror
(
"fail to get pending signal"
);
34
exit
(1);
35
}
36
37
if
(sigismember(&sig_pend, SIGUSR1 - 1) == 1)
//测试是否有SIGUSR1信号是未决的
38
printf
(
"there is a signal, SIGUSR1, is pending/n"
);
39
else
{
40
perror
(
"fail to test signal-set"
);
41
exit
(1);
42
}
43
44
if
(sigprocmask(SIG_UNBLOCK, &set, NULL) == -1){
//取消对SIGUSR1的阻塞
45
perror
(
"fail to set signal-mask"
);
46
exit
(1);
47
}
48
49
printf
(
"SIGUSR1 is available again/n"
);
50
51
return
0;
52
}
4.高级信号处理函数
原型:
#include
定义函数 int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact);
函数说明 sigaction()会依参数signum指定的信号编号来设置该信号的处理函数。参数signum可以指定SIGKILL和SIGSTOP以外的所有信号。
如参数结构sigaction定义如下
1
struct
sigaction
2
{
3
void
(*sa_handler) (
int
);
4
sigset_t sa_mask;
5
int
sa_flags;
6
void
(*sa_restorer) (
void
);
7
}
sa_handler此参数和signal()的参数handler相同,代表新的信号处理函数,其他意义请参考signal()。
sa_mask 用来设置在处理该信号时暂时将sa_mask 指定的信号搁置。
sa_restorer 此参数没有使用。
sa_flags 用来设置信号处理的其他相关操作,下列的数值可用。
OR 运算(|)组合A_NOCLDSTOP : 如果参数signum为SIGCHLD,则当子进程暂停时并不会通知父进程SA_ONESHOT/SA_RESETHAND:当调用新的信号处理函数前,将此信号处理方式改为系统预设的方式。
SA_RESTART:被信号中断的系统调用会自行重启
SA_NOMASK/SA_NODEFER:在处理此信号未结束前不理会此信号的再次到来。如果参数oldact不是NULL指针,则原来的信号处理方式会由此结构sigaction 返回。
返回值 执行成功则返回0,如果有错误则返回-1。
错误代码 EINVAL 参数signum 不合法, 或是企图拦截SIGKILL/SIGSTOPSIGKILL信号
EFAULT 参数act,oldact指针地址无法存取。
EINTR 此调用被中断
5.SA_NOCLDWAIT选项
设置SA_NOCLDWAIT选项后,当信号为SIGCHILD时,则调用进程的子进程终止,立即释放系统资源。如果调用进程调用wait函数,则会导致该进程阻塞,知道其所有的子进程全部释放后wait函数返回-1,并将errno错误号设置为ECHILD,该选项可以用来避免僵尸进程的产生。
01
//nowait.c
02
03
#include <stdio.h>
04
#include <stdlib.h>
05
#include <signal.h>
06
#include <unistd.h>
07
#include <errno.h>
08
09
int
main(
void
)
10
{
11
struct
sigaction act;
12
pid_t pid;
13
14
act.sa_handler = SIG_DFL;
15
act.sa_flags = SA_NOCLDWAIT;
16
act.sa_sigaction = NULL;
17
sigemptyset(&act.sa_mask);
18
19
if
(sigaction(SIGCHLD, &act, NULL) == -1){
20
perror
(
"fail to set handler for SIGCHILD"
);
21
exit
(1);
22
}
23
24
pid = fork();
25
26
if
(pid < 0){
27
perror
(
"fail to fork"
);
28
exit
(1);
29
}
else
if
(pid == 0){
30
printf
(
"the 1st child/n"
);
31
exit
(0);
//第一个进程立即退出
32
}
else
{
33
pid = fork();
34
35
if
(pid < 0){
36
perror
(
"fail to fork"
);
37
exit
(1);
38
}
else
if
(pid == 0){
39
printf
(
"the 2nd child/n"
);
40
sleep(5);
//休眠5秒退出
41
exit
(0);
42
}
else
{
43
if
(wait(NULL) == -1)
//调用wait函数,该函数必定出错返回
44
if
(
errno
== ECHILD)
45
printf
(
"all child quit, no child is zome/n"
);
46
47
printf
(
"the parent/n"
);
48
}
49
}
50
51
return
0;
52
}
执行:
./nowait
the 1st child
the 2nd child
all child quit, no child is zome
the parent
6.SA_NODEFER选项
如果设置SA_NODEFER选项,当捕捉到该信号时该信号正在执行处理函数时,不阻塞该信号,除非sa_mask中指定阻塞该信号。
01
//nodefer.c
02
03
#include <stdio.h>
04
#include <stdlib.h>
05
#include <signal.h>
06
07
void
sigusr1_handler(
int
signo)
08
{
09
printf
(
"catch SIGUSR1/n"
);
10
11
sleep(5);
//等待下一个SIGUSR1信号
12
13
printf
(
"back to main/n"
);
14
}
15
16
int
main(
void
)
17
{
18
struct
sigaction act;
19
20
act.sa_handler = sigusr1_handler;
21
act.sa_flags = SA_NODEFER;
22
act.sa_sigaction = NULL;
23
sigemptyset(&act.sa_mask);
24
25
if
(sigaction(SIGUSR1,&act, NULL) == -1){
26
perror
(
"fail to set handler for SIGCHILD"
);
27
exit
(1);
28
}
29
30
printf
(
"process begin/n"
);
31
32
sleep(10);
//等待SIGUSR1信号
33
34
printf
(
"done/n"
);
35
36
return
0;
37
}
7.SA_RESETHAND选项
如果设置SA_RESETHAND选项,当信号处理返回后,该信号的处理函数乎恢复为默认的信号处理函数。
01
#include <stdio.h>
02
#include <stdlib.h>
03
#include <signal.h>
04
05
void
sigusr1_handler(
int
signo)
06
{
07
printf
(
"catch SIGUSR1/n"
);
08
}
09
10
int
main(
void
)
11
{
12
struct
sigaction act;
13
14
act.sa_handler = sigusr1_handler;
15
act.sa_flags = SA_RESETHAND;
16
act.sa_sigaction = NULL;
17
sigemptyset(&act.sa_mask);
18
19
if
(sigaction(SIGUSR1, &act, NULL) == -1){
20
perror
(
"fail to set handler for SIGCHILD"
);
21
exit
(1);
22
}
23
24
printf
(
"process begin/n"
);
25
26
sleep(5);
//等待第一个SIGUSR1
27
28
sleep(5);
//等待第二个SIGUSR1
29
30
printf
(
"done/n"
);
31
32
return
0;
33
}
from:http://www.cqihang.com/index.php/archives/398
- 信号集与屏蔽字
- linux信号集与信号屏蔽字
- 信号集与屏蔽信号
- 设置信号集和信号屏蔽字
- 信号屏蔽字
- 信号屏蔽字
- linux信号屏蔽字
- 信号屏蔽字
- 信号屏蔽与信号递达
- 阻塞信号与信号屏蔽pending
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 信号集与屏蔽信号
- 信号屏蔽字&信号未决字
- 信号集和信号屏蔽函数
- APUE学习笔记——10.11~10.13 信号集、信号屏蔽字、未决信号
- APUE学习笔记——信号、信号集和进程信号屏蔽字
- select与pselect的信号屏蔽
- select与pselect的信号屏蔽
- 屏蔽信号
- C# inputBox文字输入对话框
- js弹出窗口总结6种弹窗方法
- Flex TitleWindow返回值处理
- js confirm弹出框
- c 空间点到直线的垂足及距离计算
- 信号集与屏蔽字
- 搜索引擎的工作原理 --《The Anatomy of a Large-Scale Hypertextual Web Search Engine》
- extjs xtype 一览表
- VC中添加库文件和头文件:
- 测试驱动开发简介
- Hibernate commit() 和flush() 的区别
- ora-00600 [1236] & ora-00600 [16365] & ora-04031
- feof多输出的原因 多出FF
- 堆排序的实现