打电话叫程序起床
当计算机中发生了进程需要知道的事情时,操作系统就会向进程发送信号。比如用户想中断进程或“杀死”进程,或进程企图做一件它不应该做的事情,比如访问受限存储器。
除了在发生错误时使用,有时进程也需要产生自己的信号,比如闹钟信号
SIGALRM 。闹钟信号通常由进程的间隔定时器创建。间隔定时器就像一台闹钟:你可以定一个时间,其间程序就会去做其他事情:
尽管程序正忙着做其他事,计时器还是会在后台运行,120 秒以后……
…定时器发出 SIGALRM 信号
当进程收到信号以后就会停止手中一切工作来处理信号。进程在收到闹钟信号以后默认会结束进程,但通常情况下使用定时器不是为了让它帮你“杀死”程序,而是为了利用闹钟信号的处理器去做另一件事:
闹钟信号可以实现多任务。如果需要每隔几秒运行一个任务,或者想限制花费在某个任务上的时间,就可以用闹钟信号让程序打断自己。不要同时使用 alarm() 和 sleep()。sleep() 函数会让程序沉睡一段时间。和 alarm() 函数一样,它也使用了间隔计时器,因此同时使用这两个函数会发生冲突。
重置信号与忽略信号
你已经见过如何设置自定义信号处理器了,但如果你想还原默认的信号处理器怎么办?signal.h 头文件中有一个特殊的符号 SIG_DFL ,它代表以默认方式处理信号。catch_signal(SIGTERM, SIG_DFL);
同时,你还可以用 SIG_IGN 符号让进程忽略某个信号。catch_signal(SIGINT, SIG_IGN);
在你决定忽略某个信号前一定要慎重考虑,信号是控制进程和终止进程的重要方式,如果忽略了它们,程序就很难停下来。
这里没有蠢问题问:我能把闹钟定在几分之一秒后响铃吗?答:可以是可以,但很复杂。需要用另一个函数 setitimer() ,它可以把进程间隔计时器的单位设为几分之一秒。问:具体怎么做?答:详情请见 。 http://tinyurl.com/3o7hzbm 问:为什么一个进程只有一个定时器?答:定时器由操作系统的内核管理,如果一个进程有很多定时器,内核就会变得很慢,因此操作系统需要限制进程能使用的定时器个数。问:定时器可以实现多任务?太好了,也就是说我能同时做几件事?答:非也。别忘了,进程在处理信号时会停止一切工作,也就是说一次只能做一件事,稍后会看到如何让代码同时做多件事。问:重复设置定时器会怎么样?答:每次调用 alarm() 函数都会重置定时器,也就是说如果把闹钟调到 10 秒,但过一会儿又把它设为了 10 分钟,那么闹钟信号 10 分钟以后才会触发,第一个 10 秒计时就失效了。
练习
这个程序用来测试用户的数学水平,它要求用户做乘法。程序的结束条件如下:
用户按了 Ctrl-C。
回答时间超过 5 秒。
程序在结束时会显示最终得分并把退出状态设为 0。
练习解答
这个程序用来测试用户的数学水平,它要求用户做乘法。程序的结束条件如下:
用户按了 Ctrl-C。
回答时间超过 5 秒。
程序在结束时会显示最终得分并把退出状态设为 0。
试驾
为了测试这个程序,你需要多运行几遍。
测试一:按 Ctrl-C
第一次先回答几个问题然后按 Ctrl-C。
Ctrl-C 向进程发送中断信号(
SIGINT ),程序显示最终得分然后调用 exit() 退出。
测试二:等 5 秒
第二次,不按 Ctrl-C,而是在一个问题出现后等待至少 5 秒,看看会发生什么。
闹钟信号(SIGALRM )触发了。程序在等用户输入答案,但用户花了太长时间,定时器信号被发送给了程序。程序马上跳转到 times_up() 处理器,先显示了“TIME'S UP!”消息,然后把信号升级为 SIGINT ,于是程序显示出了最后的得分。
虽然信号有些复杂,但很好用。信号可以让程序从容结束,而间隔定时器可以帮助处理一些超时任务。这里没有蠢问题问:信号按什么顺序发送,程序就会按什么顺序接收吗?答:如果两个信号发送间隔很短就不会,操作系统会先发送它认为更重要的信号。问:总是如此吗?答:取决于你的平台。例如在 Cygwin 的很多版本中,信号会按发送的顺序接收,但通常不应该做这样的假设。问:如果一个信号发送了两次,进程都会接收到吗?答:还是要看情况,在 Linux 和 Mac 中,如果一个信号在很短的时间里发送了两次,内核只会发送其中的一个;而在 Cygwin 中两个信号都会发送,但不应该做这样的假设。
要点
操作系统用信号来控制进程。
程序通常用信号来结束。
进程收到信号后会运行信号处理器。
大部分错误信号的默认处理器会终止程序。
可以用
sigaction() 函数替换处理器。
可以用 raise() 向自己发送信号。
间隔定时器发送 SIGALRM 信号。
alarm() 函数设置间隔定时器。
每个进程只能有一个定时器。
不要同时使用 sleep() 和 alarm() 。
kill 命令可以向进程发送信号。
kill -KILL 一定可以终止进程。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论