1、信号的基本概念
信号是一种进程通信的方式,又称为软件中断,一个进程一旦收到信号就会打断原来的程序执行流程来处理该信号。由于进程不知道什么时候会收到信号,因此信号通信是异步的。可以使用"kill -l"命令来查看系统所支持的信号列表。
Ctl+c是系统设置的向进程发送信号的快捷键。除了系统设置的一些,系统还提供了专门的命令和系统调用接口可以向一个进程发送信号。
每个信号都有一个名字,以SIG开头。例如:SIGABRT是夭折信号,当进程调用abort函数时,产生这种信号。SIGALRM是闹钟信号,当alarm函数设置的时间已经超过后,会产生此信号。进程对信号的处理:忽略该信号;捕捉信号(内核在某种信号发生时,执行一个用户函数);执行信号默认动作。
2、信号的影响(副作用)
重入:在一个进程里,main函数(主线程)、其它线程和信号处理函数都是独立的执行流程,他们是并行的。当他们同时访问相同的全局资源时,就有可能出现冲突。例子,向一个链表中插入数据,main和sighandler都调用insert函数则有可能出现链表的混乱,其根本原因,对全局链表的插入操作需两步完成。
3、信号处理函数
当进程收到信号时会调用信号处理函数。此外,系统还提供函数接口,供调用者产生接口。
设置信号处理函数:系统对进程接收到的信号提供了多种默认处理方式,其中一种方式就是结束接收到信号的进程。linux允许用户自定义信号处理函数,是用signal函数将处理函数加载,并通知系统,我们称此函数为信号处理程序(signal handler)或信号捕捉函数(signal-catching function)。signal函数第一个参数是要加载的要处理的信号的编号,有三种:SIG_IGN(忽略该信号),SIG_DFL(使用默认的信号处理方式),其它已定义的函数指针。信号是异步的通信方式,其到来由系统通知应用程序,所以信号处理是由系统调用的。
linux系统不允许用户创建信号,但系统提供了两种信号SIGUSR1和SIGUSR2专门用于应用程序之间信号通信。对于这两种信号,系统默认的处理方式是忽略。
在使用自定义的信号处理函数时,要现在主函数中设置信号处理函数。
4、发送信号
一个进程可以向另一个进程发送一个信号,所以信号可以用于进程间的通信。通过信号输出的信息,可以使多个进程协作完成一个任务。linux环境使用kill向进程或者进程组发送信号。一个进程向另一个进程发送信号必须注意一下几点:该进程有向指定进程发送信号的权限;系统进程不能接收信号,例如init进程。如果kill函数发送成功则返回0,失败则返回-1。
向进程本身发送信号。linux同样提供向进程本身发送信号的函数,该函数是raise:int raise(int signo);
5、设置linux定时器
时间是编程中的一个重要概念,有些场合需要设置一个时间定时器。在经过若干时间后通知设置定时器的进程。linux环境下使用alarm函数设置一个定时器,其函数原型如下:
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
参数表示定时器设置的秒数,从设置定时器开始,如果系统时间超过该时间后就会向调用alarm函数的进程发送一个SIGALRM信号,这个信号的默认动作是终止调用alarm函数的进程。每个进程只能有一个闹钟时间。
定时等待I/O。对外设进行读写操作时,有时会出现外设不可用状态。例如,网络设备中等待的数据包未到达等。这时就会导致读写操作的阻塞,这种阻塞是没有时间限制的,直到所请求的设备准备好为止。alarm函数可以实现定时阻塞,当需要读写的设备没有就绪时,只等待有限的时间。
挂起进程。阻塞、就绪和运行是进程的3个状态。任何时刻只有一个进程处于运行状态。当进程的运行条件已经具备时,进程处于就绪状态;当运行的条件不具备时,进程处于阻塞状态,处于就绪状态的进程可以被调度,阻塞态的进程由于不可以运行,所以不能被调度。有时一个进程的运行条件具备时仍需要把其阻塞(例如期望进程延时执行,sleep函数起这个作用)。这种进程自愿进入阻塞态的情况就叫做进程挂起。linux环境下使用pause函数挂起一个进程,其函数原型如下:
#include <unistd.h>
int pause(void);
pause函数使使用该函数的进程进入挂起状态。直到一个信号到来,执行了一个信号处理程序并从其返回,pause函数才返回,返回值为-1。(?)
调用pause函数使得进程不再响应SIGTERM等许多信号,唯一杀死进程的方法是使用kill命令向进程发送SIGKILL信号。
进程休眠。pause函数是使进程无时间限制挂起,若想使进程在一段时间内恢复执行,则使用sleep函数。
6、信号集与屏蔽信号
屏蔽信号是linux系统的一个重要功能,可以使用户有选择的接收信号并且处理信号。需要屏蔽的信号使用信号集来表示。
信号集是一个表示多个信号的数据类型,sigset_t set ,则set就是一个信号集,可以对信号集进行一些删除、设置操作。
有时希望阻塞一些信号,即使进程接收到信号,也不对信号做处理。阻塞一个信号称为信号屏蔽,每个进程内都有一个信号屏蔽字,标记被屏蔽的信号。linux环境下使用sigprocmask函数设置信号屏蔽字。
7、高级信号注册函数
现代linux系统提供了一个改进版的信号注册函数sigaction函数。
8、abort函数
该函数的功能是程序异常终止。此函数将SIGABRT信号发送给调用进程。进程不忽略此信号。