日期:2014-05-16  浏览次数:20917 次

UNIX/Linux进程间通信IPC系列(五)信号

信号


信号是软件中断。它允许进程中断其他进程。

信号是异步处理事件的经典实例。产生信号的事件对进程而言是随机出现的。进程不能简单地测试一个变量(例如errno)来判别是否出现了一个信号,而是必须告诉内核“在此信号出现时,请执行下列操作”

一个信号就是一条小消息,它通知进程系统中发生了一个某种类型的事件。每种信号类型都对应于某种系统事件。低层的硬件异常是由内核异常处理程序处理的,正常情况下对用户进程而言是不可见的。

信号提供了一种机制,通知用户进程发生了这些异常(由内核发送给用户进程)。如果一个进程试图除以0,那么内核就发给它一个SIGFPE信号。

 

发送信号


内核通过更新目的进程上下文的某个状态,发送(递送)一个信号给目的进程。

发送信号可以有如下两个原因:

内核检测到一个系统事件,比如被零除错误或子进程终止。

一个进程调用了kill函数显示地要求内核发送一个信号给目的进程。一个进程可以发送信号给它自己。


从键盘发送信号

在键盘上输入ctrl-c会导致一个SIGINT信号被被发送到外壳。外壳捕获该信号,然后发送SIGINT信号到这个前台进程组中的每个进程。(在默认情况下,结果是终止前台作业)

类似地,输入ctrl-z会发送一个SIGSTP信号到外壳,外壳捕获这个信号,并发送SIGSTP信号给前台进程组中的每个进程。(在默认情况下,结果是挂起前台作业)

 

用/bin/kill程序发送信号

/bin/kill程序可以向另外的进程发送任意的信号。

比如,命令 /bin/kill  -9 15213 发送一个信号9(SIGKILL)给进程15213。

一个为负的PID会导致信号被发送到进程组PID中的每个进程,比如:

命令 /bin/kill  -9 -15213  发送一个SIGKILL信号给进程组15213中的每个进程。

 

用kill函数发送信号

进程通过调用kill函数发送信号给其他进程(包括它们自己)

如果pid大于0,那么kill函数发送信号sig给进程pid。如果pid小于0,那么kill发送信号sig给进程组abs(pid)中的每个进程。

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

int main(void)
{
    pid_t pid ;

    if ((pid = fork()) == 0)
    {
        pause() ;
        printf("control should never reach here!\n") ;
        exit(0) ;
    }

    kill(pid, SIGKILL) ;
    exit(0) ;
}

用alarm函数发送信号

进程可以通过调用alarm函数向它自己发送SIGALRM信号

#include <unistd.h>

unsigned int alarm(unsigned int secs) ;

alarm函数安排内核在secs秒内发送一个SIGALRM信号给调用进程。

如果secs是0则删除闹钟。

//alarm函数可以设置一个计时器。当计时器超时时,产生SIGALRM信号。
//如果不忽略或不捕捉此信号,则其默认动作时终止调用该alarm函数的进程
//每个进程只能有一个闹钟时钟
//
//该程序每隔3秒打印一个alarm!
//
#include <unistd.h> //包含alarm()
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>

static void sig_alarm(int) ;

int 
main(void)
{
   int i = 0 ;
    //绑定信号与信号处理函数
    if (signal(SIGALRM, sig_alarm) == SIG_ERR)
        perror("can't catch SIGALARM") ;

   for (i = 0; i < 3; ++i)
   {
       ala