unix-关于信号、信号处理函数

来源:互联网 发布:unix高级编程 编辑:程序博客网 时间:2024/04/29 22:01

信号是发生某件事时对进程的通知,它不可以被预知。信号可以来自其它进程或者进程本身,也可以是来自内核。

每个信号都有一个处理办法(disposition),也称作与信号关联的行为(action),一般有三种处理方法:

1 提供一个函数(signal handler),在信号发生时调用,这称之为捕获(catching)。

2 设置信号的处理办法为SIG_IGN,忽略它,但有两种信号是不能忽略的:SIGKILL、SIGSTOP。

3 SIG_DFL可以设置缺省处理办法,一般是收到信号时终止进程。当然,也可以忽略它们,例如SIGCHLD和SIGURG。


POSIX中定义信号处理函数用sigaction函数,处理函数的指针做为填充在做为参数之一的struct sigaction结构中,当然还有函数所对应的需要处理的信号,原型如下:

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

UNP中为sigaction做了一个包裹函数:

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

它与非POSIX的signal函数一致,就是向操作系统登记要处理的信号。信号处理函数在登记完成后便一直有效。信号处理函数在执行时,可以通过设置sa_mask来指定要屏蔽的其实信号。此时被屏蔽(阻塞)的信号是不排队的。当然,在实时UNIX系统中不会阻塞信号,所有的信号排队接受处理。

UNIX对信号的处理不排队,这个特性就是说:当同时有若干个信号,只捕获第一个,其它的就被抛弃了。可以想像一个服务器同时连接着很多客户机,当若干个客户同时断开连接,服务器处理这些客户的进程结束后几乎同时向父进程发送SIGCHLD信号。只有第一个SIGCHLD被处理了,其它的信号会屏蔽掉,子进程仍会处于僵尸状态(Zombie)。

处理这种情况要使用waitpid函数,它比wait提供更多控制机制,下面就是一个典型的SIGCHLD信号处理函数:

void sig_chld(int signo)

{

pid_t pid;

int stat;

while((pid = waitpid(-1, &stat, WNOHANG))>0)

printf("child %d terminated./n", pid);

return ;

}

waitpid中pid设为-1表示等侍第一个终止的子进程,WNOHANG表示在没有已终止子进程时不要阻塞。

Posix信号处理部分总结

       POSIX 表示可移植操作系统接口,英文全称为:Portable Operating System Interface ,IEEE最初开发POSIX标准,是为了提高UNIX环境下应用程序的可移植性,但POSIX并不局限与UNIX,许多其他的操作系统都支持POSIX标准 
   
      看了几天的Unix网络编程中Posix信号处理这章内容,了解了些关于signal的相关知识,现在总结下:
       
      首先,要知道什么是信号,信号是事件发生时对进程的通知,又可以称为软中断; 
       其次,信号是如何产生的,书中描述有2种可能,一是进程间的相互发送,二是由内核产生并发送至进程;
       最后,信号如何捕获和处理呢,下面具体说明的

      看了书中的代码以及相关的说明以后,我在网上查了下signal的相关处理函数以及signal.h的头文件定义,可以利用索引查到相关的函数和头文件说明
      这个网址是
http://www.opengroup.org/onlinepubs/009695399/

       网上的对关于signal的处理方法做了如下的说明:

       The signal() function chooses one of three ways in which receipt of the signal number sig is to be subsequently handled.
       If the value of func is SIG_DFL, default handling for that signal shall occur.
       If the value of func is SIG_IGN, the signal shall be ignored.
       Otherwise, the application shall ensure that func points to a function to be called when that signal occurs.

       上面一共描述了三种方法:

       首先是可以设置默认的信号处理方法(SIG_DFL),默认的信号处理方法一般为接受到该信号时终止进程,个别信号的缺省处理方法是忽略
           signal(SIGCHLD,SIG_DFL) --将SIGCHLD信号的处理方法设置为缺省的处理方法
       其次是可以设置忽略的信号处理方法(SIG_IGN),但是有2个信号是不可以忽略的
           SIGKILL  Kill(cannot be caught or ignored).
           SIGSTOP  Stop executing (cannot be caught or ignored).

           signal(SIGALRM,SIG_IGN) --将SIGALRM信号的处理方法设置为忽略的处理方法

       最后是可以指定自定义的信号处理方法
           简单的方法是用signal函数,它的第一个参数是信号名,第二个参数是指向函数的指针或为常值SIG_DFL或SIG_IGN
           但是,我们还可以利用sigaction自定义自己的信号处理函数

           struct sigaction sa;
           sa.sa_handler = 函数名;
           sigemptyset(&sa.sa_mask);
           sa.sa_flags = SA_RESTART;/* Restart functions if interrupted by handler */
           if (sigaction(SIGINT, &sa, NULL) == -1)
             /* Handle error */;

       这就是signal的一些处理方法和步骤,但有时候我们并不用系统直接提供的signal函数,而是利用sigaction自己构造信号的特定处理方法
       但是还有点迷惑的是就是对SA_RESTAR的定义不是很了解,还得多差点资料

       上述的网站上是对SA_RESTART做下面的解释的:
       This flag affects the behavior of interruptible functions; that is, those specified to fail with errno set to [EINTR]. 
       If set,and a function specified as interruptible is interrupted by this signal,the function shall restart and shall not fail with [EINTR] unless specified. 
       If the flag is not set, interruptible functions interrupted by this signal shall fail with errno set to [EINTR]
 
       书中是这样解释的:如果设置,由此信号中断的系统调用将由内核自动重启
      
       最后,还有一个名词就是慢系统调用(slow system call),永远阻塞的系统调用是指调用可能永远无法返回,慢系统调用一般就是来描述可能永远阻塞的系统调用
       比如:
           1、如果没有客户机连接到服务器上,则服务器的accept的调用就没有返回保证了