1. 信号是软件中断:
信号提供了一种处理异步事件的方法. 每个信号都有一个名字, 他们以SIG开头,
如SIGALRM是闹钟信号, 当由alarm函数设置的计时器超时后产生此信号, 然后由SIGALRM的信号处理函数接管处理,
处理之后返回调用alarm函数的应用程序中.
2. 信号编号:
在头文件中,
信号都用宏定义为正整数的信号编号, 不存在编号为0的信号,
kill函数对编号为0的信号有特殊的作用. POSIX.1将编号为0的信号定义为空信号, 如果kill中的signo参数为0,
则kill仍执行正常的错误检查, 但不发送信号. 这常被用来通过kill的返回值确定一个特定进程是否存在.
3. 不可忽略/捕捉的信号:
大多数信号都可以通过忽略进行处理, 但SIGKILL和SIGSTOP这两个信号不能被忽略(不能捕获).
因为它们是向超级用户提供使进程终止或停止的可靠方法. 另外, 如果忽略某些硬件异常产生的信号(例如非法内存引用或除0),
则进程的行为是未定义的.
4. 介绍几个常见信号:
SIGINT: 当用户按某些终端键时, 引发终端产生的信号.
如Ctrl+C键, 这将产生中断信号(SIGINT). 它将停止一个已失去控制的程序.
SIGSEGV: 由硬件异常(除数为0,
无效的内存引用等等)产生的信号. 这些条件通常由硬件检测到, 并将其通知内核.
然后内核为该条件发生时正在运行的进程产生该信号.
SIGURG: 在网络连接上传来带外数据时产生.
SIGPIPE: 在管道的读进程已终止后,
一个进程写此管道时产生. 当类型为SOCK_STREAM的socket已不再连接时, 进程写到该socket也产生此信号.
SIGALRM:
进程所设置的闹钟时钟超时的时候产生.
SIGABRT: 进程调用abort函数时产生此信号,
进程异常终止.
SIGCHLD: 在一个进程终止或停止时, 它将把该信号发送给其父进程. 按系统默认,
将忽略此信号. 如果父进程希望被告知其子进程的这种状态改变, 则应该捕捉此信号. 通常是用wait系列函数捕捉, 如果不wait的话,
子进程将成为一个僵尸进程.
SIGIO: 此信号指示一个异步I/O事件.
SIGSYS: 该信号指示一个无效的系统调用.
SIGTSTP: 交互式停止信号. Ctrl+Z, 按下时,
终端将产生此信号, 进程被挂起.
1. 原型:
#include
void (*signal(int signo, void (*func)(int))(int));
成功则返回该信号以前的处理配置, 出错则返回SIG_ERR.
参数说明:
signo: 信号名, 如SIGINT.
func: 对应signo的信号处理函数的函数名, 这个函数没有返回值, 有一个整型参数, 这是捕捉的情况,
当然也可以是以下两种宏:
SIG_IGN: 忽略.
SIG_DFL: 默认动作.
2. 改写原型:
typedef void (*sigfunc)(int);
sigfunc *signal(int, sigfunc);
3. 三个宏定义:
#define SIG_ERR (void (*)()) -1 // 错误编号
#define SIG_DFL (void (*)()) 0 // 默认动作编号
#define SIG_IGN (void (*)()) 1 // 忽略编号
4. kill命令:
在shell里面执行kill命令可以向进程发送信号:
kill -USR1 7216 ;向pid为7216的进程发送SIGUSR1信号.
kill
7216 ;向pid为7216的进程发送SIGTERM信号.
5. 注意事项:
exec函数执行后, 把该进程所有信号设为默认动作.
exec函数执行后, 把原先要捕捉的信号设为默认, 其他不变.
fork之后, 子进程继承父进程的信号处理方式.