[10 信号]使用signal函数捕获信号并处理

1 signal介绍

先看下函数声明:

#include <signal.h>
//若成功,返回该Unix系统信号之前的信号处理函数地址;若失败,返回SIG_ERR
void (*signal(int signo, void (*func)(int)))(int);

signo参数是Unix系统信号。
func的值是常量SIG_IGN,常量SIG_DFL或当收到此信号后要调用的函数地址。若指定SIG_IGN,则向内核表示忽略此信号(注意,SIGKILL和SIGSTOP不能忽略);若指定SIG_DFL,则表示接收到此信号的动作是系统默认动作;若指定信号处理函数时,我们称这种处理为捕捉该信号。
使用如下的typedef可简化声明:

typedef void Sigfunc(int);
Sigfunc *signal(int , Sigfunc *);

注意:signal函数的形参表示的函数指针指的是对该Unix系统信号设置的信号处理函数;
signal函数的返回值表示的函数指针表示该Unix系统信号之前的信号处理函数。
而函数指针的返回值为空,形参为一个int值。
如果查看头文件<signal.h>,可以找到如下声明:

#define SIG_ERR (void (*)())-1
#define SIG_DFL (void (*)())0
#define SIG_IGN (void (*)())1

这些常量表示"指向函数的指针,该函数要求一个整型参数,而且无返回值"。

2 使用signal函数捕获信号并处理

如下程序捕捉两个用户定义的信号。

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

static void sig_usr(int);    /* one handler for both signals */

int main(void)
{
    void (*func1)(int);
    void (*func2)(int);

    if ( (func1 = signal(SIGUSR1, sig_usr)) == SIG_ERR) {
        printf("can't catch SIGUSR1 \n");
    } else {
        printf("catch SIGUSR1 func1:%p \n", func1);
        // signal返回值表示对信号SIGUSR2之前的信号处理函数,SIG_DFL
        if (func1 == SIG_DFL) {
            printf("func1 == SIG_DFL \n");
        }
    }

    if ( (func2 = signal(SIGUSR2, sig_usr)) == SIG_ERR) {
        printf("can't catch SIGUSR2 \n");
    } else {
        printf("catch SIGUSR2 1 func2:%p \n", func2);
        // signal返回值表示对信号SIGUSR2之前的信号处理函数,SIG_DFL
        if (func2 == SIG_DFL) {
            printf("func2 == SIG_DFL \n");
        }
    }

    if ( (func2 = signal(SIGUSR2, sig_usr)) == SIG_ERR) {
        printf("can't catch SIGUSR2 \n");
    } else {
        printf("catch SIGUSR2 2 func2:%p \n", func2);
        // signal返回值表示对信号SIGUSR2之前的信号处理函数,sig_usr
        if (func2 != NULL) {
            func2(77);
        }
    }

    for ( ; ; ) {
        pause();
        printf("after pause <<<<<<< \n");
    }
}

static void sig_usr(int signo)        /* argument is signal number */
{
    if (signo == SIGUSR1)
        printf("received SIGUSR1\n");
    else if (signo == SIGUSR2)
        printf("received SIGUSR2\n");
    else
        printf("received signal %d\n", signo);
}

pause函数会使调用函数在接收到一个信号前挂起。
我们使该程序在后台运行,并用kill命令将信号发送给它。

$ ./sigusr &
[2] 4015
catch SIGUSR1 func1:(nil)
func1 == SIG_DFL
catch SIGUSR2 1 func2:(nil)
func2 == SIG_DFL
catch SIGUSR2 2 func2:0x4006f7
received signal 77
$ kill -USR1 4015
received SIGUSR1
after pause <<<<<<<
$ kill -USR2 4015
received SIGUSR2
after pause <<<<<<<
$ kill 4015

该程序不捕捉SIGTERM信号,对该信号的系统默认动作是终止。

3 注意

1 启动程序
exec函数将原来设置为要捕获的信号都更改为默认动作,因为信号捕获函数的地址在所执行的新的程序文件中已无意义。
2 创建进程
当一个进程调用fork时,其子进程继承父进程的信号处理方式。因为子进程开始复制了父进程的内存映像,所以信号捕获函数的地址在子进程中是有意义的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值