一、信号
1、简介
信号是软件中断,提供了一种处理异步事件的方法,可作为进程间通信的一种机制。
每个信号都有一个以SIG开头名称,例如SIGINT、SIGALRM等。这些信号名称在signal.h中以宏的形式定义,对应一个正整数(信号编号)。
以下情形可以产生一个信号
当用户在终端键入某些组合键时,如Ctrl+C键产生中断信号(SIGINT)。
硬件异常产生信号。例如:除数为0、非法的内存访问等。
进程调用kill函数将信号发送给另一个进程或进程组。
用户在shell命令行,使用kill命令将信号发送给其他进程。
kill -<信号名> <PID>
killall -<信号名> <命令名>
当检测到某种软件异常时产生信号。
波特率不符产生SIGURG
写无读进程的管道产生SIGPIPE
闹钟超时产生SIGALRM
信号是一种典型的异步事件,产生信号的事件对进程而言是随机出现的。
当信号产生时,可有三种处理方式:忽略、捕获或执行默认操作。
忽略信号。
大多数信号均可忽略。
SIGKILL和SIGSTOP不能被忽略,因为它们为超级用户提供了一种使进程终止或停止的可靠方法。
某些由硬件异常产生的信号(例如非法的内存访问或除以0)也不应被忽略。
捕获信号。让内核在信号产生时调用事先设置好的回调函数。
执行系统默认动作。
信号列表(未捕获时会引起进程终止的信号)
信号名称 | 说明 |
SIGABORT | 调用abort函数时产生,进程将异常终止。 |
SIGALRM | 超时。一般由alarm设置的定时器产生。 |
SIGFPE | 浮点运算异常,如除以0和浮点溢出。 |
SIGHUP | 终端关闭或断开连接。由处于非连接状态的终端发给控制进程或由控制进程在自身结束时发给每个前台进程。 |
SIGILL | 非法指令。通常由一个崩溃的程序或无效的共享内存模块引起。 |
SIGINT | 程序终止,一般由从终端敲入的中断字符(Ctrl + C)产生。 |
SIGKILL | 终止进程(此信号不能被捕获或忽略),一般在shell中用它来强制终止异常进程。 |
SIGPIPE | 向管道写数据时没有与之对应的读进程时产生。 |
SIGQUIT | 程序退出。一般由终端敲入的退出字符(Ctrl + \)产生。 |
SIGSEGV | 无效内存段访问。一般是因为对内存中的无效地址进行读写引起,如数组越界、解引用无效指针。 |
SIGTERM | kill命令默认发送的信号,要求进程结束运行。UNIX在关机时也用此信号要求服务停止运行。 |
SIGUSR1 | 用户定义信号1,用于进程间通信。 |
SIGUSR2 | 用户定义信号2 ,用于进程间通信。 |
信号名称 | 说明 |
SIGABORT | 调用abort函数时产生,进程将异常终止。 |
SIGALRM | 超时。一般由alarm设置的定时器产生。 |
SIGFPE | 浮点运算异常,如除以0和浮点溢出。 |
SIGHUP | 终端关闭或断开连接。由处于非连接状态的终端发给控制进程或由控制进程在自身结束时发给每个前台进程。 |
SIGILL | 非法指令。通常由一个崩溃的程序或无效的共享内存模块引起。 |
SIGINT | 程序终止,一般由从终端敲入的中断字符(Ctrl + C)产生。 |
SIGKILL | 终止进程(此信号不能被捕获或忽略),一般在shell中用它来强制终止异常进程。 |
SIGPIPE | 向管道写数据时没有与之对应的读进程时产生。 |
SIGQUIT | 程序退出。一般由终端敲入的退出字符(Ctrl + \)产生。 |
SIGSEGV | 无效内存段访问。一般是因为对内存中的无效地址进行读写引起,如数组越界、解引用无效指针。 |
SIGTERM | kill命令默认发送的信号,要求进程结束运行。UNIX在关机时也用此信号要求服务停止运行。 |
SIGUSR1 | 用户定义信号1,用于进程间通信。 |
SIGUSR2 | 用户定义信号2 ,用于进程间通信。 |
2、捕获信号
最简单的捕获信号的方式是调用signal函数
signum 准备捕获或忽略的信号.
handler 捕获到信号后由系统调用的回调函数。特殊值:
SIG_IGN 忽略信号.
SIG_DFL 恢复默认行为.
返回值
成功时返回原先定义信号处理函数,如果原先未定义则返回SIG_ERR,并设置errno为一正数值。
出错时,如果给出的是一个无效的信号或不可捕获或不可忽略的信号,则返回SIG_ERR,并设置errno为EINVAL。
进程启动时,所有信号的状态都为系统默认或忽略。
调用exec函数会将原先设置为要捕捉的信号都更改为默认动作。
当一个进程调用fork创建子进程时,其子进程继承了父进程的信号处理方式。
shell程序会自动将后台进程中对中断和退出信号的处理方式设置为忽略。
当用户在命令行按Ctrl+C或Ctrl+\键时就不会影响到后台进程。
3、发送信号
进程可以调用kill函数给自己或其他进程发送信号。
pid 接收信号的进程PID.
sig 要发送的信号.
返回值 成功0;失败-1,并设置errno。常见的errno值为:
EINVAL 给定的信号无效.
EPERM 发送进程权限不够.
ESRCH 目标进程不存在.
发送方进程应具有相应的权限,满足以下两个条件之一:
接收信号进程和发送信号进程的所有者相同.
发送信号的进程的所有者是超级用户.
4、alarm、pause和sleep函数
alarm函数可为进程设置一个定时器,在设定的时间到达时,产生SIGALRM信号。
seconds 指定几秒后产生SIGALRM信号,0表示取消设置.
返回值 成功时返回以前设置的定时器时间的余留秒数;失败 时返回0。
每个进程只能有一个定时器。
alarm设置的定时器并非周期性的定时器,即调用一次只产生一次SIGALRM信号。
alarm函数设置的定时器并不能精确定时执行。
调用pause函数可使调用进程挂起直至捕捉到一个信号.
返回值 直到进程捕获到一个信号并从该信号的信号处理程序中 返回时,pause函数才返回,返回值为-1,并设置 errno为EINTR。
sleep函数使进程睡眠若干秒。
返回值 返回值为所设时间的余留秒数。
sleep函数使调用进程挂起直到
已经过了seconds所指定秒数
捕捉到一个信号并从信号处理程序返回.
5、abort
abort函数的功能是使程序异常终止。
abort函数将SIGABRT信号发送给调用进程。进程不应忽略此信号。
进程捕捉SIGABRT后可在进程终止之前执行必要的清理操作。当信号处理程序返回时,abort即终止进程。
6、信号集
数据类型sigset_t用于存放一个信号集。头文件signal.h中声明了sigset_t和五个信号集处理函数。
set 信号集.
sig 信号.
返回值
成功时,sigismeber函数返回1或0;其他函数返回0。
失败时返回-1,并设置errno,错误代码EINVAL,表示给定的信号无效。
函数sigemptyset初始化由set指向的信号集,使其排除所有信号。
sigfillset初始化由set指向的信号集,使其包括所有信号。
7、sigaction
sigaction是一个比signal更健壮的用于捕获信号的编程接口。
sig 准备捕获或忽略的信号.
act 将要设置的信号处理动作.
oldact 用于取回原先的信号处理动作.
返回值 成功时返回0;失败时返回-1,并设置errno变量。 EINVAL表示无效的、不可捕获或不可忽略的信号。
如果act指针非空,则表示要修改sig信号的处理动作。如果oldact指针非空,则系统在其中返回该信号的原先动作。
struct sigaction.
sa_flags
SA_NOCLDSTOP 子进程停止时不产生SIGCHLD信号。
SA_RESETHAND 在信号处理函数入口处将对此信号的处理方式重置 为SIG_DFL。
SA_RESTART 重启可中断的函数而不是给出EINTR错误。
SA_NODEFER 捕获到信号时不将它添加到信号屏蔽字中,即不自 动阻塞当前捕获到的信号。
一旦对给定的信号设置了一个动作,那么在用sigaction改变它之前,该设置就一直有效。