Linux信号和信号处理

Linux信号列表



     名称     默认动作   说明

  SIGHUP  终止进程     终端线路挂断

  SIGINT  终止进程     中断进程
  
  SIGQUIT 建立CORE文件 终止进程,并且生成core文件

  SIGILL 建立CORE文件 非法指令

  SIGTRAP 建立CORE文件 跟踪自陷

  SIGBUS 建立CORE文件 总线错误

  SIGSEGV 建立CORE文件 段非法错误

  SIGFPE 建立CORE文件 浮点异常

  SIGIOT 建立CORE文件 执行I/O自陷

  SIGKILL 终止进程 杀死进程

  SIGPIPE 终止进程 向一个没有读进程的管道写数据

  SIGALARM 终止进程 计时器到时

  SIGTERM 终止进程 软件终止信号

  SIGSTOP 停止进程 非终端来的停止信号

  SIGTSTP 停止进程 终端来的停止信号

  SIGCONT 忽略信号 继续执行一个停止的进程

  SIGURG 忽略信号 I/O紧急信号

  SIGIO 忽略信号 描述符上能进行I/O

  SIGCHLD 忽略信号 当子进程停止或退出时通知父进程

  SIGTTOU 停止进程 后台进程写终端

  SIGTTIN 停止进程 后台进程读终端

  SIGXGPU 终止进程 CPU时限超时

  SIGXFSZ 终止进程 文件长度过长

  SIGWINCH 忽略信号 窗口大小发生变化

  SIGPROF 终止进程 统计分布图用计时器到时

  SIGUSR1 终止进程 用户定义信号1

  SIGUSR2 终止进程 用户定义信号2

  SIGVTALRM 终止进程 虚拟计时器到时


信号处理:


进程在收到信号以后,有三种方法处理所接收到的信号:
1接受默认动作,通常是终止进程的执行。
2彻底忽略信号的发生,并继续执行程序。
3接受用户自定义的默认动作。


信号集:

信号集是与处理信号的系统调用相关的主要参数,指明你想处理的一些信号列表。
  #include<signal.h>
初始化:应用程序在使用信号集之前应该至少调用一次sigemptyset或sigfillset.
int sigemptyset(sigset_t *set);清空信号集中的所有信号量
int sigfillset (sigset_t *set);设置信号集中的所有信号量

操作:
int sigaddset(sigset_t *set,int signo);添加信号量到信号集中

int sigdelset(sigset_t *set,int signo);删除信号量到信号集中

例如:
#include<signal.h>

sigset_t mask1,mask2;
.
.
.
/*create empty set */
sigemptyset(&mask1);
/*add signal*/
sigaddset(&mask1,SIGINT);

/*create full set */
sigfillset(&mask2);

/*del signal*/
sigdelset(&mask2,SIGCHLD);
.
.
.



设置信号处理动作:sigaction


#include<singal.h>

int sigaction(int signo,const struct sigaction *act,
                               struct sigaction *oact);
          第一个参数signo指定需要处理的特定信号,应该在signo类型信号收到之前就调用sigaction。
          第二个参数act设定signo信号的处理动作。
          第三个参数oact返回的是此信号的当前设置值。act和oact的值都可能是NULL.        

头文件<signal.h>中定义的sigaction结构:
struct sigaction
{
    void (*sa_handler)(int);
    sigset_t sa_mask
    
    int sa_flags;
    
    void (*s_sigaction)(int ,siginfo_t *,void*);
};

 void (*sa_handler)(int):
sa_handler指定接收到信号signo后的处理函数。它可以为三种值:
1  SIG_DEL是一个比较特殊的符号值,它表示恢复系统定义的默认处理函数(通常是终止进程)
2  SIG_IGN表示忽略此信号.SIGKILL和SIGSTOP不能忽略
3  一个函数地址,该函数只有一个整型参数。只要该参数声明在调用sigaction之前,sa_handler就
可以设为该函数的名字,当进程接收到信号signo时,就会以signo为参数执行这个函数。也就是说,当进程
收到signo信号时,不管它在执行什么程序,控制立即转向sigaction所设的处理函数。当该函数返回时,
控制返回到进程中断的位置。
  
    sigset_t sa_mask:
    在执行处理函数sa_handler时,系统会阻塞sa_mask所指定的信号量。但这并不意味着它们被系统忽略了,
    这些信号只不过被系统延迟到处理函数执行完之后再处理。
    
    int sa_flags:
    用来改变signo信号的行为属性。比如把sa_flags设为SA_RESETHAND,使得在执行完该信号处理函数后,
信号处理函数重新设为SIG_DFL.设置为SA_RESTART的情况:在大多数情况下,如果进程在做系统调用时
收到信号,那么直到系统调用完成之前,信号都不会起作用。然而有些系统调用却是例外,它们可以被
信号中断,例如在慢速设备(终端)上的read,write或open调用。通过设置sa_flags=SA_RESTART可以重新启动
被中断系统调用。


捕获SIGINT信号


sigex.c:
/* sigex----------shows how sigaction works */
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<stdio.h>

int main(void)
{
    static struct sigaction act;//设置为静态变量,使得系统把结构的各个成员初始化为零

    /*declare catchint,later to be use as the handler */
    void catchint(int);//信号处理函数

    /*set up the action to be taken on receipt of SIGINT */
    act.sa_handler=catchint;

    /* create a full mask */
    sigfillset(&(act.sa_mask));//设置所有的信号,意味着阻塞所有的信号,除了signo参数的信号
    
    /* before sigaction call,SIGINT will 
     * terminate process (default action) */




//未调用信号处理函数之前
    printf("no sigaction call:#1\n");
   sleep(1);
    printf("no sigaction call:#2\n");
    sleep(1);
    printf("no sigaction call:#3\n");
  sleep(1);

    printf("no sigaction call:#4\n");
    sleep(1);
    printf("use sigaction call\n");


//调用信号处理函数
    sigaction(SIGINT,&act,NULL);

    /*on receipt of SIGINT control will be passed
     * to catchint
     */

    printf("sleep call #1\n");
    sleep(1);
    printf("sleep call #2\n");
    sleep(1);
    printf("sleep call #3\n");
    sleep(1);
    printf("sleep call #4\n");
    sleep(1);

    printf("Exiting...\n");
    exit(0);
}

/*trivial function to handler SIGINT */

void catchint(int signo)
{
    printf("\nCATCHINT:signo=%d\n",signo);

    printf("CATCHINT :returning \n\n");
}



运行结果:
//未调用信号处理函数之前被中断,程序简单的终止
jiang@jiang-linux:~/unixprog/2011-3-18$ ./sigex.o 
no sigaction call:#1
no sigaction call:#2
no sigaction call:#3
^C

//调用信号处理函数后被中断,控制转入信号处理函数,函数终止后控制还回到程序被中断的那一点上。
jiang@jiang-linux:~/unixprog/2011-3-18$ ./sigex.o 
no sigaction call:#1
no sigaction call:#2
no sigaction call:#3
no sigaction call:#4
use sigaction call
sleep call #1
sleep call #2
^C
CATCHINT:signo=2
CATCHINT :returning 

sleep call #3
sleep call #4
Exiting...



忽略SIGINT


 如果一个进程想忽略中断信号SIGINT,把程序下面的这一行:
act.sa_handler=catchint;
改为
act.sa_handler=SIG_IGN;
执行该语句之后,中断键对该程序无效。

也可以再次打开信息的处理:
act.sa_handler=SIG_DEF;//表示恢复系统定义的默认处理函数
sigaction(SIGINT,&act,NULL);

可以很好的同时忽略几种信号,例如:
act.sa_handler=SIG_IGN;
sigcation(SIGINT,&act,NULL);
sigcation(SIGQUIT,&act,NULL);
同时处理SIGINT和SIGQUIT信号。
对于一个已经忽略了某些信号的进程来说,它将在exec后继续忽略这些信号。所以命令
解释程序可以调用sigcation以确保忽略SIGQUIT和SIGINT信号,然后执行新的程序。

恢复到先前的动作


sigcation可以填充第三个参数ocat,使得用户可以保存并恢复信号之前的状态。如:
#include<signal.h>

static struct sigcation act,oact;

/* save the old action for SIGTERM*/
sigcation(SIGTERM,NULL,&oact);

/*set new action for SIGTERM */
act.sa_handler=SIG_IGN;
sigcation(SIGTERM,&act,NULL);//忽略信号

/* do the work here....*/

/*now restore the old action */
sigcation(SIGTERM,&oact,NULL);

一个完美的退出


假设一个程序使用了临时工作文件,下面这段代码的作用是删除这个文件:
/*exit from program gracefully*/
#include<stdio.h>
#include<stdlib.h>

void g_exit(int s)
{
    unlink("tempfile");
  fprintf(stderr,"Interrupted---exiting\n");
 exit(1);
}

可以把这段代码与一个特定的信号联系起来:
extern void g_exit(int s);
.
.
.
static struct sigcation act;
act.sa_handler=g_exit;
sigcation(SIGINT,&act,NULL);
当程序运行时,一旦用户按下中断键,控制就自动从主程序转向g_exit.从而完成清理工作。



发送信号到其他进程中:kill

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

int ntime=0;

int main(void)
{
    pid_t pid,ppid;
    static struct sigaction pact,cact;
    void p_action(int signo);//parent signal action
    void c_action(int signo);//chile signal action

    /*set SIGUSR1 action for parent */
    pact.sa_handler=p_action;
    sigaction(SIGUSR1,&pact,NULL);

    switch(pid=fork())
    {
        case-1://error
            perror("synchor");
            exit(1);
        case 0://child
            /*set action for child*/
            cact.sa_handler=c_action;
            sigaction(SIGUSR1,&cact,NULL);

            /*get parent pid*/
            ppid=getppid();

            for(;;)
            {
                sleep(1);
                kill(ppid,SIGUSR1);
                pause();
            }
        default:/*parent*/
            for(;;)
            {
                pause();
                sleep(1);
                kill(pid,SIGUSR1);
            }
    }
}

void p_action(int sig)
{
    printf("Parent caught signal # %d\n",ntime);
}

void c_action(int sig)
{
    printf("Child caught signal # %d\n",++ntime);
}


结果:


jiang@jiang-linux:~/unixprog/2011-3-19$ gcc synchro.c -o synchro.o;./synchro.o 
Parent caught signal # 0
Child caught signal # 1
Parent caught signal # 0
Child caught signal # 2
Parent caught signal # 0
Child caught signal # 3
Parent caught signal # 0
Child caught signal # 4
Parent caught signal # 0
Child caught signal # 5
Parent caught signal # 0
^C
//同时也说明了父进程和子进程有不同的变量,


alarm系统调用


#include<unistd.h>

unsigned int alarm(unsigned int secs);
在alarm调用中,secs给出了定时器超时的时间,当给定时间超时后,进程将收到一个SIGALRM信号,
可以捕获该信号进行处理。



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

#define    TIMEOUT    5  /*in seconds*/
#define    MAXTRIES    5
#define LINESIZE    100
#define CTRL_G '\007'
#define TRUE 1
#define    FALSE    0

/* used to see if timeout has occured*/
static int time_out;

/* will hold input file */
static char answer[LINESIZE];

char *quickreply(char *prompt)
{
    void catch(int signo);
    int ntries;
    static struct sigaction act,oact;

    /*catch SIGALRM+save previous action */
    act.sa_handler=catch;
    sigaction(SIGALRM,&act,&oact);

    for(ntries=0;ntries<MAXTRIES;ntries++)
    {
      time_out=FALSE;
        printf("\n%s>",prompt);

        /*set alarm clock*/
        alarm(TIMEOUT);

        /*get input file*/
    fgets(answer,100,stdin);

        /*turn off alarm*/
        alarm(0);

        /*if time_out TRUE,then no reple*/
        if(!time_out)
        {
            break;
        }
    }
    /*restore old action*/
    sigaction(SIGALRM,&oact,NULL);
    /*return appropriate value*/
    return (ntries==MAXTRIES?((char *)0):answer);

}

/*executed when SIGALRM received*/
void catch(int signo)
{
    /*set timeout flag*/
    time_out=TRUE;

    /*ring bell*/
    putchar(CTRL_G);
}

int main(void)
{
  char *p="Please input command:";
  char *result;
    result=quickreply(p);
    if(result==NULL)
    {
        printf("input command time out!\n");
        return -1;

    }
    else
    {
        printf("input command successful!\n");
    }

    return 0;
}


结果:
jiang@jiang-linux:~/unixprog/2011-3-19$ ./alarm.o 

Please input command:>jiang
input command successful!
jiang@jiang-linux:~/unixprog/2011-3-19$ ./alarm.o 

Please input command:>
Please input command:>
Please input command:>
Please input command:>
Please input command:>input command time out!


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值