曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 6207|回复: 1
打印 上一主题 下一主题

[信号] signal() -- 信号捕捉与处理

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34397
跳转到指定楼层
楼主
发表于 2009-7-3 16:08:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
函数原型
#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 标志,即表示我们希望受阻塞的系统调用被该信号中断。

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34397
沙发
 楼主| 发表于 2009-7-25 03:35:28 | 只看该作者

sighandler_t 类型

sighandler_t 是信号处理函数类型,在 signal.h 中有定义:
#ifdef __USE_GNU
typedef __sighandler_t sighandler_t;
#endif

还有:
/* Type of a signal handler.  */
typedef void (*__sighandler_t) (int);

__sighandler_t 可以用来定义一个指向带有 int 型参数且无返回值函数( 信号处理函数就是这样的类型 )的指针。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-6-19 06:12 , Processed in 0.094275 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表