10 信号处理——signal、sigaction

1、signal

各种事件促使内核向进程发送信号,包括用户的击键、进程的非法操作和计时器到时,一个进程调用signal在一下3种处理信号的方法之中选择:

  • 默认操作(一般是终止进程),如signal(SIGALRM,SIG_DEL)
  • 忽略信号,如signal(SIGALRM,SIG_IGN)
  • 调用一个函数,如signal(SIGALRM,handler)

signal的缺陷:signal处理根据不同版本不同选择

  • 不可靠的信号:如果两个SIGINTS信号杀死了进程,意味着你的系统是不可靠信号,处理函数必须每次都重置。如果多个SIGINTS信号没有杀死进程,意味着处理函数在被调用后还起作用。signal处理根据不同版本不同选择。
  • SIGX打断SIGY的处理函数:当接连按下CTRL-C和CTRL-\会看到程序先跳到inthandler,接着跳到quithandler,然后再回到inthandler,最后回到主循环。
  • SIGX打断SIGX的处理函数:这种情况有三种处理方式,分别是递归、忽略第二个信号、阻塞第二个信号直至第一个处理完毕
  • 被中断的系统调用:在系统调用时接收到信号,在AT&T的Unix中是返回并设置EINTR为-1,在UCB中会自动重新开始
  • 不知道信号被发送的原因
  • 处理函数中不能安全地阻塞其他消息

2、sigaction

在POSIX中用sigaction替代signal,解决上诉缺陷。

sigaction系统调用:

  • sigaction():指定一个信号的处理函数,res=sigaction(int signum,const struct sigaction *action,struct sigaction *preaction),signum是要处理的信号,action指向描述如何响应信号的结构体,preaction指向描述被替换的处理设置的结构体。

(1)定制信号处理:struct sigaction

结构体sigaction定义了如何处理一个信号

struct sigaction {
               void     (*sa_handler)(int);
               void     (*sa_sigaction)(int, siginfo_t *, void *);
               sigset_t   sa_mask;
               int        sa_flags;
               void     (*sa_restorer)(void);
           };

(2)选择sa_handler还是sa_sigaction

要在老的信号处理方式和新的更强大的信号处理方式之间作出选择。如果老的处理方式(SIG_DEL、SIG_IGN、handler)够用了,那么可以设置sa_handler为其中之一。如果设定sa_sigaction为一个处理函数,name那个处理函数被调用的时候,不但可以得到信号编号而且可以获悉被调用的原因以及产生问题的上下文的相关信息。设置sa_flags的SA_SIGINFO位来告诉内核使用新的信号处理方式。

(3)sa_flags

sa_flags用一些位来控制处理函数如何应对上述4个问题。

  • SA_RESETHAND:当处理函数被调用时重置,也就是采用捕鼠器模式
  • SA_NODEFER:当处理信号时关闭信号自动阻塞,允许递归调用信号处理函数
  • SA_RESTART:当系统调用是针对一些慢速的设备或类似的系统调用,重新开始,而不是返回,采用BSD模式
  • SA_SIGINFO:指明使用sa_sigaction的处理函数的值。如果这个位没设置,使用sa_handler指定的处理函数的值

(4)sa_mask

sa_mask决定在处理一个信息时是否阻塞其他信号。sa_mask中的位指定哪些信号要被阻塞。sa_mask的值包括要被阻塞的信号集。

3、信号总结

一个进程可能被各种来源的信号中断。信号可能在任何时候以任何顺序到达。signal提供一种简单但是不完整的信号处理机制。POSIX接口,sigaction提供了复杂的、明确定义的方法来控制进程如何处理这些信号组合做出反应

4、编写信号处理程序

sigdemo3.c

signal信号处理方式的程序

#include<stdio.h>
#include<signal.h>
#include<string.h>
#define INPUTLEN 100
void inthandler(int s)
{
    printf("Received signal %d..waiting\n",s);
    sleep(2);
    printf("Leaving inthandler\n");
}
void quithandler(int s)
{
    printf("Received signal %d..waiting\n",s);
    sleep(3);
    printf("Leaving quithandler\n");
}
int main()
{
    char input[INPUTLEN];
    int nchars;
    signal(SIGINT,inthandler);
    signal(SIGQUIT,quithandler);
    do{
        printf("\nType a message\n");
        nchars=read(0,input,(INPUTLEN-1));
        if(nchars==-1)
            perror("read returned an error");
        else
        {
            input[nchars]='\n';
            printf("You typed: %s",input);
        }
    }while(strncmp(input,"quit",4)!=0);
    return 0;
}

sigactdemo.c

sigaction信号处理的程序

#include<stdio.h>
#include<signal.h>
#define INPUTLEN 100
void inthandler(int s)
{
    printf("Called with signal %d\n",s);
    sleep(s);
    printf("done handling signal %d\n",s);
}
int main()
{
    struct sigaction newhandler;
    sigset_t blocked;
    char x[INPUTLEN];
    newhandler.sa_handler=inthandler;
    newhandler.sa_flags=SA_RESETHAND | SA_RESTART;
    sigemptyset(&blocked);
    sigaddset(&blocked,SIGQUIT);
    newhandler.sa_mask=blocked;
    if(sigaction(SIGINT,&newhandler,NULL)==-1)
        perror("sigaction");
    else
        while(1)
        {
            fgets(x,INPUTLEN,stdin);
            printf("input:%s",x);
        }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值