●信号
◎基本概念:信号机制是一种一步的通知机制,用来提醒进程一个事件已经发生。当一个信号发送给一个进程,操作系统中断了进程正常的控制流程,此时,任何非原子操作都将被中断。如果进程定义了信号的处理函数,那么它将被执行,否则就执行默认的处理函数。举个例子:
①用户输入命令,在shell下启动一个前台进程;
②用户键盘输入Ctrl+C产生一个硬件中断。如果当前CPU正在执行这个程序的代码,则代码暂停执行,CPU从用户态切到内核态来处理这个硬件中断;
③终端驱动程序将Ctrl+C解释成SIGINT信号,记录在该进程的PCB中;
④当某个时刻要从内核态返回该进程用户空间代码继续执行,首先要处理PCB中记录的信号,发现有一个SIGINT信号未处理,而这个信号的默认处理动作是终止进程,所以直接终止进程而不再返回它的用户空间代码执行。
◎简单分类:使用 kill -l 命令可以查看系统定义的信号列表:
对这些信号做一个简单的分类:1~31这31个信号称为非实时信号,它们不支持排队,都不可靠;而34~64这31个信号是实时信号,支持排队,都是可靠信号。
●信号的产生
产生信号的主要方式有:①通过终端按键产生信号;②调用系统函数向进程发信号;③由软件条件产生信号。
◎通过终端按键产生信号:
用户在终端按下某些键时,终端驱动程序会向前台进程发送信号。比如Ctrl+C产生SIGINT信号,Ctrl+\产生SIGQUIT信号,Ctrl+Z产生SIGTSTP信号等。
其中,SIGTSTP信号的默认处理动作是终止进程并且Core Dump。Core Dump是指当一个进程异常终止时,可以选择把进程的用户空间内存数据全部保存到磁盘上,文件名通常为core。进程异常终止通常是因为由Bug,事后可以通过调试器检查core文件以查找错误原因,这叫做Post-mortem Debug(事后调试)。默认是不允许产生core文件的,但开发调试阶段可以用ulimit命令改变这个限制,允许产生core文件。
ulimit -a (显示当前所有的资源限制):
ulimit -c 1024 (允许core文件最大为1024k):
在前台执行一个死循环程序,然后在终端键入Ctrl+\:
这时会生成一个core文件,接着就可以使用core文件了:
◎调用系统函数向进程发信号:
命令部分学过,利用kill命令可以发送信号给某个进程,而kill命令是调用kill函数实现的。当内核检测到某种软件条件发生时已可以通过信号通知进程,比如闹钟超时产生SIGALRM信号,向读端已关闭的管道写数据时产生SIGPIPE信号等。
在后台执行死循环程序,用kill命令向它发送SIGSEGV信号:
kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号。
raise函数可以给当前进程发送指定信号(自己向自己发送信号)。
运行结果:
◎由软件条件产生信号:
调用alarm函数可以设定一个闹钟,即告诉内核在seconds秒之后给当前进程发送SIGALRM信号,该信号的默认处理动作是终止当前进程。
这个程序的作用是1秒之内一直累加,1秒之后被SIGALRM信号终止。
运行结果:
●处理动作
◎忽略此信号
◎执行该信号的默认处理信号
◎提供一个信号处理函数,要求内核在出炉该信号时切换到用户态执行这个处理函数,这种方式称为捕捉一个信号。
signal函数