Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2153285
  • 博文数量: 333
  • 博客积分: 10161
  • 博客等级: 上将
  • 技术积分: 5238
  • 用 户 组: 普通用户
  • 注册时间: 2008-02-19 08:59
文章分类

全部博文(333)

文章存档

2017年(10)

2014年(2)

2013年(57)

2012年(64)

2011年(76)

2010年(84)

2009年(3)

2008年(37)

分类: LINUX

2012-09-10 18:23:41

写在前面

1.          本文内容对应《UNIX环境高级编程》(2)》第10章。

2.          总结了有关信号的基本概念,包括信号产生的原因和对信号的处理方式。

3.          希望本文对您有所帮助,也欢迎您给我提意见和建议。

信号概念

信号是软件中断,提供了一种处理异步事件的方法。每个信号都有一个名字,以字符SIG开头,定义为正整数。在linux下,目前有31种不同的信号,定义在中。不存在编号为0的信号。很多条件可以产生信号:

l          当用户按某些终端键时,引发终端产生的信号,如中断(Ctrl+CSIGINT)、退出(Ctrl+/SIGQUIT)和挂起(Ctrl+ZSIGTSTP)键。

l          硬件异常产生信号,如除数为0、浮点溢出(SIGFPE),无效的内存引用(SIGSEGV)等。

l          进程调用kill函数可将信号发送给另一个进程或进程组。

l          用户可用kill命令将信号发送给其它进程。常用此命令终止一个失控的后台进程。

l          当检测到某种软件条件已经发生,并应将其通知有关时也产生信号,如进程所设置的定时器到期时产生SIGALRM

当某个信号出现时,可以以三种方式之一进行处理:

l          忽略信号。有两种信号(SIGKILLSIGSTOP)不能被忽略,它们向超级用户提供了使进程终止或停止的可靠方法。

l          捕捉信号。为做到这一点,要通知内核在某种信号发生时调用一个用户函数。不能捕捉SIGKILLSIGSTOP信号。

l          执行系统默认动作。针对大多数信号的系统默认动作是终止进程。

捕捉信号

要捕捉一个信号,最简单的方式是调用signal函数为它指定一个信号处理函数。

#include

void (*signal(int signo, void (*func)(int)))(int);

signo参数是信号名,func参数的值是常量SIG_IGN(忽略)、SIG_DFL(默认)或信号处理函数的地址。信号处理函数接收信号名作为参数,并且没有返回值。signal函数的返回值是SIG_IGNSIG_DFL或指向之前的信号处理函数的指针,若出错则返回SIG_ERR。当一个进程调用fork时,其子进程继承父进程的信号处理方式。但exec函数将原先设置为要捕捉的信号都更改为它们的默认方式,因为原信号处理函数可能在所执行的新程序中并无定义。

         值得注意的是,在进入信号处理函数中,将屏蔽当前信号。信号屏蔽的概念将在以后解释。

可重入函数

进程捕捉到信号并对其进行处理时,进程正在执行的指令序列就被信号处理函数临时中断。它首先执行该信号处理函数中的指令。如果从信号处理函数返回(如没有调用exitlongjmp),则继续执行在捕捉到信号时进程正在执行的正常指令序列(类似于硬件中断)。但在信号处理函数中,不能判断捕捉到信号时进程在何处执行。因此,在信号处理函数中应当调用可重入函数。否则,其结果是不可预见的。

不可重入函数的原因主要是:1)使用静态数据结构;2)调用mallocfree3)是标准IO函数,标准IO库德很多实现都以不可重入方式使用全局数据结构。

由于每个线程只有一个errno变量,所以信号处理函数可能会修改其原先值。作为一个通用的规则,当在信号处理函数中调用可能修改errno值的函数时,应当在其前保存,在其后恢复errno

         实验程序如下:

#include "apue.h"

#include

 

void sig_quit(int signo)

{

     int old_errno;

 

     old_errno = errno;          /*save for restoration*/

     write(STDOUT_FILENO, "receive SIGQUIT./n", 18);

     pr_mask("in sig_quit: ");

     errno = old_errno;

}

 

int main()

{

     pid_t pid;

 

     if( signal(SIGQUIT, sig_quit) == SIG_ERR)   /*shared by child*/

       printf("signal SIGQUIT error./n");

     if( (pid = fork()) < 0)

     {

       printf("fork error./n");

       exit(EXIT_FAILURE);

     }

     pause();

     exit(EXIT_SUCCESS);

}

         运行结果为:

pydeng@pydeng-laptop:~/apue.2e/mytest$ ./a.out

^/receive SIGQUIT.

in sig_quit:

receive SIGQUIT.

in sig_quit:


阅读(1245) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~