linux通信机制signal()函数详解

  我们来谈一谈signal()函数的作用。

  linux系统提供了signal()和sigaction()两个函数来改变对于信号的处理方法。其中signal()是一个基于sigaction()系统调用的glibc库函数,其行为在不同的linux操作系统存在差异,对于可移植性有要求的程序不能使用signal()函数。


1.什么是信号?

  信号(signal)是一种进程间通信机制,它给应用程序提供一种异步的软件中断,使应用程序有机会接受其他程序活终端发送的命令(即信号)。应用程序收到信号后,有三种处理方式:忽略,默认,或捕捉。进程收到一个信号后,会检查对该信号的处理机制。如果是SIG_IGN,就忽略该信号;如果是SIG_DFT,则会采用系统默认的处理动作,通常是终止进程或忽略该信号;如果给该信号指定了一个处理函数(捕捉),则会中断当前进程正在执行的任务,转而去执行该信号的处理函数,返回后再继续执行被中断的任务。

  信号的本质是异步。异步一这个词,听着高端大气上档次,又让人云山雾绕,其则不然。其实我们想想,我们这个世界是异步的,每个人干事儿,并不总是A->B->C->D这种。比如我在网上买了东西,我其实并不知道快递几时能到。我可能在公司里面,在喝水,在回邮件,在查bug,在写代码,突然收到了快递小哥的电话,注意这就是信号的delivery。由于快递的到来,我不得不停下我手头的活儿,去签收快递。这就是传说中的典型的异步。我不知道快递小哥几时给我电话,但是我收到电话就去签收,这是我的信号处理函数。更高级一点,如果我在参加重要的会议,我可能需要屏蔽快递小哥的电话(假如我知道其电话),这已经是linux下信号的高级应用(sigprocmask)了。
    信号是一种机制,是在软件层次对中断机制的一种模拟,内核让某进程意识到某特殊事情发生了。强迫进程去执行相应的信号处理函数。至于信号的来源可能来自硬件如按下键盘或者硬件故障(如ctrl+c发送SIGINT),可能来自其他进程(kill,sigqueue),可能来自自己进程(raise)。 
    信号的本质是一种进程间的通信,一个进程可以向另一个进程发送信号。


2.函数原型

在signal.h头文件中,它的声明如下:


#include <signal.h>
void (*signal(int sig_num, void (*handler)(int))(int);

成功则返回该信号以前的处理配置, 出错则返回SIG_ERR.

让我们一步步地从外向内去理解:

前面说到,signal函数返回值是函数指针,这个指针指向的函数名如下:

    void (*fp) (int)      //pointer to a function 

对应到上面的函数原型,这里的 fp 相当于

  signal (int sig_num, void (*handler)(int))  

如此一来,函数就易于理解地多了。

这里面的机制是这样的,内外有两层函数。内层是void(*handle)(int)  signal(int sig_num,void(*handler)(int)),也就是说signal函数接收了一个函数指针作为参数,又把这个函数作为了返回值,传给fp,fp再去调用这个函数。

这个函数有两个参数,第一个参数sig_num指明了所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号。第二个参数,是一个无返回值、接受一个int形参的函数指针。函数的第二个参数可以有三种选择,第一种是我们自己定义的信号处理函数,第二种是传入SIG_DFL 表示将之前signal所改变的信号处理方式还原,第三种是传入SIG_IGN,表示处理方式为忽略该信号,内核会直接将信号丢弃,不会传递到进程。

signal函数的返回值同样是一个无返回值、接受一个int形参的函数指针。当signal()函数成功执行时,返回值是执行signal函数之前的sig信号的处理函数的指针,如果失败,则返回SIG_ERR(-1)。


3.参数详解

以下是参数sig_num

SignalDescription
SIGABRT由调用abort函数产生,进程非正常退出
SIGALRM用alarm函数设置的timer超时或setitimer函数设置的interval timer超时
SIGBUS某种特定的硬件异常,通常由内存访问引起
SIGCANCEL由Solaris Thread Library内部使用,通常不会使用
SIGCHLD进程Terminate或Stop的时候,SIGCHLD会发送给它的父进程。缺省情况下该Signal会被忽略
SIGCONT当被stop的进程恢复运行的时候,自动发送
SIGEMT和实现相关的硬件异常
SIGFPE数学相关的异常,如被0除,浮点溢出,等等
SIGFREEZESolaris专用,Hiberate或者Suspended时候发送
SIGHUP发送给具有Terminal的Controlling Process,当terminal被disconnect时候发送
SIGILL非法指令异常
SIGINFOBSD signal。由Status Key产生,通常是CTRL+T。发送给所有Foreground Group的进程
SIGINT由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程
SIGIO异步IO事件
SIGIOT实现相关的硬件异常,一般对应SIGABRT
SIGKILL无法处理和忽略。中止某个进程
SIGLWP由Solaris Thread Libray内部使用
SIGPIPE在reader中止之后写Pipe的时候发送
SIGPOLL当某个事件发送给Pollable Device的时候发送
SIGPROFSetitimer指定的Profiling Interval Timer所产生
SIGPWR和系统相关。和UPS相关。
SIGQUIT输入Quit Key的时候(CTRL+\)发送给所有Foreground Group的进程
SIGSEGV非法内存访问
SIGSTKFLTLinux专用,数学协处理器的栈异常
SIGSTOP中止进程。无法处理和忽略。
SIGSYS非法系统调用
SIGTERM请求中止进程,kill命令缺省发送
SIGTHAWSolaris专用,从Suspend恢复时候发送
SIGTRAP实现相关的硬件异常。一般是调试异常
SIGTSTPSuspend Key,一般是Ctrl+Z。发送给所有Foreground Group的进程
SIGTTIN当Background Group的进程尝试读取Terminal的时候发送
SIGTTOU当Background Group的进程尝试写Terminal的时候发送
SIGURG当out-of-band data接收的时候可能发送
SIGUSR1用户自定义signal 1
SIGUSR2用户自定义signal 2
SIGVTALRMsetitimer函数设置的Virtual Interval Timer超时的时候
SIGWAITINGSolaris Thread Library内部实现专用
SIGWINCH当Terminal的窗口大小改变的时候,发送给Foreground Group的所有进程
SIGXCPU当CPU时间限制超时的时候
SIGXFSZ进程超过文件大小限制
SIGXRESSolaris专用,进程超过资源限制的时候发送

这些都是定义好的宏,有的时候也会用数字做参数:

SIGHUP 1 A 终端挂起或者控制进程终止

SIGINT 2 A 键盘中断(如break键被按下)

SIGQUIT 3 C 键盘的退出键被按下

SIGILL 4 C 非法指令

SIGABRT 6 C 由abort(3)发出的退出指令

SIGFPE 8 C 浮点异常

SIGKILL 9 AEF Kill信号

SIGSEGV 11 C 无效的内存引用

SIGPIPE 13 A 管道破裂: 写一个没有读端口的管道

SIGALRM 14 A 由alarm(2)发出的信号

SIGTERM 15 A 终止信号

SIGUSR1 30,10,16 A 用户自定义信号1

SIGUSR2 31,12,17 A 用户自定义信号2

SIGCHLD 20,17,18 B 子进程结束信号

SIGCONT 19,18,25 进程继续(曾被停止的进程)

SIGSTOP 17,19,23 DEF 终止进程

SIGTSTP 18,20,24 D 控制终端(tty)上按下停止键

SIGTTIN 21,21,26 D 后台进程企图从控制终端读

SIGTTOU 22,22,27 D 后台进程企图从控制终端写




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值