函数原型:
#include <signal.h>
typedef void (*sighandler_t) (int);
sighandler_t signal(int signum, sighandler_t handler); signal() 会根据参数 signum 指定的信号编号来设置该信号的处理函数。当指定的信号到达时就会跳转到参数 handler 指定的函数执行。如果参数 handler 不是函数指针,则必须是常数 SIG_IGN (忽略该信号) 或 SIG_DEF (对该信号执行默认操作)。handler 是一个函数指针,它所指向的函数的类型是 sighandler_t,即它所指向的函数有一个 int 型参数,且返回值的类型是 void 。
signal() 函数执行成功时,返回以前的信号处理函数指针,当有错误发生时,则返回 SIG_ERR( -1 )。
测试程序:
#include <stdio.h>
#include <signal.h>
void handler_sigint(int signo)
{
printf("recv SIGINT\n");
}
int main()
{
signal(SIGINT, handler_sigint);
while(1)
;
return 0;
} 在程序执行时,用户在终端按下 ctrl + c 组合键向进程发送 SIGINT 信号,最后按下 ctrl + \ 组合键向进程发送 SIGQUIT 信号。由于程序本身没有处理 SIGQUIT 信号,按照默认处理方式,进程退出( 也可以使用 kill 命令结束进程 )。
此函数现在已不推荐使用,但在许多老的程序可以看到其身影,现在推荐使用 sigaction() 函数--http://www.groad.net/bbs/read.php?tid=909
对于 signal() 函数的返回值的说明可以用下面代码来演示:
[C++] 纯文本查看 复制代码 #include <stdio.h>
#include <stdlib.h>
#include <signal.h>
static void sig_handler_int(int sig)
{
printf ("int_ok\n");
}
static void sig_handler_tstop(int sig)
{
printf ("tstop_ok\n");
}
int main()
{
int j;
unsigned long addr;
printf ("sig_handler_int : 0x%u\n", (unsigned long)sig_handler_int);
printf ("sig_handler_tstop : 0x%u\n", (unsigned long)sig_handler_tstop);
addr = (unsigned long)signal(SIGINT, sig_handler_int);
printf ("0x%u\n", addr);
addr = (unsigned long)signal(SIGINT, sig_handler_tstop);
printf ("0x%u\n", addr);
return 0;
}
运行输出:$ ./handler
sig_handler_int : 0x134513760
sig_handler_tstop : 0x134513780
0x0
0x134513760 当第一次运行 signal() 安装 sig_handler_int 时,它之前从没有安装过任何信号处理函数,因此返回 0 。第二次运行 signal() 时,由于之前已经安装了 sig_handler_int ,因此它的返回值就是 sig_handler_int() 函数的地址。
虽然建立信号处理的 POSIX 方法是调用 sigaction() 函数,但它自身有点复杂。但是我们可以将 sigaction() 函数被包裹在我们自定义的 signal() 函数中,这样在调用的起来就显得简单明了,比如:
[C++] 纯文本查看 复制代码
typedef void Sigfunc (int);
Sigfunc * signal(int signo, Sigfunc *func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask); //设置处理函数信号掩码,这里设置为空集,表示在该信号处理函数运行期间,不阻塞额外的信号
act.sa_flags = 0;
if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
#endif
} else {
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */
#endif
}
if (sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
}
如果被捕捉的信号不是 SIGALRM 并且设置 SA_RESTART 标志,那么表示被信号中断的系统调用将由内核自动重启。另外,我们通常为 I/O 操作设置超时处理(使用信号 SIGALRM -- 可由 alarm() 函数超时发出),那么在这种情况下我们就设置 SA_INTERRUPT 标志,即表示我们希望受阻塞的系统调用被该信号中断。 |