来源:http://www.fengyj.net/blog/?p=434
由于历史原因,signal在各种平台上的实现可能会不尽相同,而POSIX明确规定调用sigaction函数的语义,但sigaction函数调用往往比较复杂,解决方法是用sigaction实现自己的signal函数,signal函数原型:
1.
void
(*
signal
(
int
signo,
void
(*handle)(
int
)))(
int
);
其中signal接受两个参数,一个int型的信号编码,另一个处理信号的函数指针,然后返回一个之前定义的处理信号的函数的指针,处理函数接受一个int型参数,返回void,这样看起来挺麻烦的,简单点可以这样定义:
1.
typdef
void
(SIG_HANDLE)(
int
);
2.
SIG_HANDLE *
signal
(
int
, SIG_HANDLE *);
好了,知道了signal的基本语义了,现在可以用sigaction实现它了,代码如下:
01.
#include <signal.h>
02.
03.
/*
04.
* 用sigaction实现signal
05.
*/
06.
07.
typedef
void
(SIG_PROC)(
int
);
08.
09.
SIG_PROC *_signal(
int
signo, SIG_PROC *sig_proc)
10.
{
11.
struct
sigaction act;
12.
struct
sigaction oact;
13.
14.
act.sa_handler = sig_proc;
15.
// 设置信号处理函数的信号掩码:信号处理函数调用期间,除屏蔽本信号外,不阻塞其他信号,信号处理函数执行完毕后,信号屏蔽字恢复到之前的值
16.
sigemptyset(&act.sa_mask);
17.
act.sa_flags = 0;
18.
19.
// 除了SIGALRM以外的其他信号,如果被中断都将尝试重新启动(linux下)
20.
if
(signo == SIGALRM)
21.
{
22.
#ifdef SA_INTERRUPT
23.
act.sa_flags |= SA_INTERRUPT;
24.
#endif
25.
}
26.
else
27.
{
28.
#ifdef SA_RESTART
29.
//如果设置了restart,内核将重启被中断的系统调用,系统调用不会返回-1
30.
act.sa_flags |= SA_RESTART;
31.
#endif
32.
}
33.
34.
if
(sigaction(signo, &act, &oact) < 0)
35.
{
36.
return
SIG_ERR;
37.
}
38.
return
oact.sa_handler;
39.
}
顺便说一下,信号一般由其他进程或内核发送给进程,对信号的处理有3种方式,分别为自己定义信号处理函数、忽略该信号和采用默认的方式:
- 自定义信号处理函数:SIGKILL和SIGSTOP不能被捕获
- 忽略信号:将信号的处理设置为SIG_IGN,SIGKILL和SIGSTOP不能被忽略
- 默认处理:将信号处理设置为SIG_DFL,大多数情况的默认处理是终止进程,极个别的信号采用忽略方式,如SIGCHLD,SIGURG(带外数据到达时发送)
信号 | 值 | 动作 | 解释 |
SIGHUP | 1 | 终端线路挂断 | |
SIGINT | 2 | Term | 键盘输入的中断命令,从终端输入 Ctrl-C 时发生 |
SIGQUIT | 3 | Core | 键盘输入的退出命令 |
SIGILL | 4 | Core | 错误指令 |
SIGABRT | 6 | Core | abort(3)发出的中止信号 |
SIGFPE | 8 | Core | 浮点数异常 |
SIGKILL | 9 | Term | KILL信号 |
SIGSEGV | 11 | Core | 非法内存访问 |
SIGPIPE | 13 | Term | 管道断开 |
SIGALRM | 14 | Term | alarm(2)发出的中止信号 |
SIGTERM | 15 | Term | 强制中止信号 |
SIGUSR1 | 30,10,16 | Term | 用户自定义信号1 |
SIGUSR2 | 31,12,17 | Term | 用户自定义信号2 |
SIGCHLD | 20,17,18 | Ign | 子进程中止信号 |
SIGCONT | 19,18,25 | Cont | 继续执行一个停止的进程 |
SIGSTOP | 17,19,23 | Stop | 非终端来的停止信号 |
SIGTSTP | 18,20,24 | Stop | 终端来的停止信号 |
SIGTTIN | 21,21,26 | Stop | 后台进程读终端 |
SIGTTOU | 22,22,27 | Stop | 后台进程写终端 |