10.10 alarm以及pause函数

alarm函数
pause函数
Example
Example
Example
Example

alarm函数

alarm函数允许我们设置一个在未来的某一时刻终止的定时器,当定时器终止的时候,SIGALRM信号就被发出,如果我们忽略或者不捕获这一信号的话,该信号的默认行为是终止进程.

  1. #include <unistd.h>
  2. unsigned int alarm(unsigned int seconds);
  3. Returns:0 or number of seconds until previously set alarm.

seconds的数值指定了未来信号生成所需要的秒数,当事件到达,信号就会被内核生成,虽然在进程获得控制权开始处理信号之前会因为处理器调度而多花一些额外的时间。

早期版本的UNIX系统实现可以允许信号被提前1秒中发送,但是POSIX.1并不允许这种行为。

这些alarm时钟对于每一个进程来说只能至多拥有一个,如果,当我们调用alarm的时候,之前注册的一个alarm时钟还没有终止,那么早先设置的alarm时钟剩余的描述将被alarm函数作为返回值返回。同时前一个时钟将会被新的数值替换掉。

如果之前注册的alarm时钟还没有终止,而本次调用alarm函数的参数seconds为0,那么前一次alarm定时就会被取消,前一次设置的alarm时钟剩余的秒数将被作为函数的返回值返回。

虽然SIGALRM信号的默认处理是终止进程,但是许多实用alarm时钟的进程会捕获这一信号。如果我们需要捕获信号SIGALRM,我们必须小心:必须在调用alarm之前安装信号处理函数,否则可能由于在信号处理函数安装之前先收到了SIGALRM信号而导致进程终止.

pause函数

函数pause用于挂起当前进程,直到捕获到一个信号:

  1. #include <unistd.h>
  2. int pause(void);
  3. Returns:-1 with errno set to EINTR

pause返回的唯一的时间是一个信号处理函数被调用,然后该信号处理函数返回,在这种情况下,pause将返回-1,并且将errno设置为EINTR.

Example

使用函数alarm以及pause,我们可以将一个进程放到睡眠状态一段指定的时间,函数sleep1就是为了达成这一目的,但是正如后面将会看到的,该函数有一个问题.

  1. #include <signal.h>
  2. #include <unistd.h>
  3. static void sig_alrm(int signo)
  4. {
  5. /*nothing to do ,just return to wake up the pause*/
  6. }
  7. unsigned int sleep1(unsigned int seconds)
  8. {
  9. if(signal(SIGALRM, sig_alrm) == SIG_ERR)
  10. {
  11. return (seconds);
  12. }
  13. alarm(seconds); /*start the timer*/
  14. pause(); /*next caught signal wakes us up*/
  15. return(alarm(0));/*turn off timer,return unslept time*/
  16. }

该函数看起来与函数sleep差不多,但是这个简单的实现有三个问题:

  1. 我们已经修改了SIGALRM信号的处理函数。如果我们正在编写一个函数给其他函数调用,我们就必须在设置我们函数的时候保存之前设置的函数,并在我们的函数运行完成之后恢复信号的处理函数。我们可以通过保存signal信号的返回值并在我们函数返回之前重新设置信号的处理函数即可。
  2. 如果调用进程已经安装了一个alarm,那么之前安装的alarm将会被sleep1函数中的第一个alarm函数擦除,我们可以根据alarm函数的返回值来纠正这一错误,如果之前设置的定时器剩余的秒数小于当前准备设置的秒数,那么就不应该再设置当前的秒数了,而是应该设置之前定时器剩余的秒数;如果之前设置的定时器剩余的秒数大于我们正准备设置的秒数,那么在我们返回之前,我们应该将定时器重新以使得定时器仍然能够在其预定的时间完成。
  3. 在第一次对alarm函数调用到对pause函数的调用之间存在一个竞态条件,因为定时器可能在我们调用pause之前就已经完成了,同时在pause之前调用了信号处理函数,这样一来,调用进程就将因为对于pause函数的调用而永远处于挂起状态(假设并没有捕获到其他信号)

早期版本的sleep函数与我们的上述程序比较相似,但是解决了其中提到的第1和2个问题。对于第三个问题有两种方式改正,第一种是使用函数setjmp,该函数我们将在下一章中讲解,另一种方式是使用函数sigprocmask以及sigsuspend,我们将在10.19中进行讲述。

Example

SVR2实现中的sleep函数使用了函数setjmp以及longjmp来避免上面提到的竞态条件的出现,该函数的一个简单版本,称为sleep2,如图10.8中显示的那样,(为了减小该函数的尺寸,我们并没有解决上述提到的问题1以及问题2).

  1. #include <setjmp.h>
  2. #include <signal.h>
  3. #include <unistd.h>
  4. static jmp_buf env_alrm;
  5. static void sig_alrm(int signo)
  6. {
  7. longjmp(env_alrm, 1);
  8. }
  9. unsigned int sleep2(unsigned int seconds)
  10. {
  11. if(signal(SIGALRM, sig_alrm) == SIG_ERR)
  12. return (seconds);
  13. if(setjmp(env_alrm) == 0)
  14. {
  15. alarm(seconds); /*start the timer*/
  16. pause(); /*next caught signal wake us up*/
  17. }
  18. return (alarm(0)); /*turn off timer,return unslept time*/
  19. }

Figure 10.8 Another (imperfect )implementation of sleep

函数sleep2避免了图10.7中的竞态条件问题,即使pause函数从来没有被执行过,当SIGALRM信号出现的时候,sleep2总是会成功返回。

然而,当我们涉及到与其他信号进行交互的时候,sleep2就会出现一个微妙的错误:如果SIGALRM中断了一些其他信号处理函数,然后当我们执行函数longjmp的时候,我们就会终止掉其他的信号处理函数,图10.9显示了这样的一个场景,在SIGINT处理函数中有一个循环,该循环保证了系统需要执行该函数5S以上,我们的目标是时期执行时间超过sleep2的参数,整形变量k被声明为volatile,是为了防止编译器优化的时候丢弃这个循环。

  1. #include "apue.h"
  2. unsigned int sleep2(unsigned int);
  3. static void sig_int(int);
  4. int main(void)
  5. {
  6. unsigned int unslept;
  7. if(signal(SIGINT, sig_int) == SIG_ERR)
  8. {
  9. err_sys("signal(SIGINT) error");
  10. }
  11. unslept = sleep2(5);
  12. printf("sleep2 returned:%u\n", unslept);
  13. exit(0);
  14. }
  15. static void sig_int(int signo)
  16. {
  17. int i,j;
  18. volatile int k;
  19. /*
  20. * Tune these loops to run for more than 5 seconds
  21. * on wahtever system this test program is run.
  22. *
  23. */
  24. printf("\nsig_int starting\n");
  25. for(i = 0; i < 300000; i++)
  26. for(j = 0; j < 4000; j++)
  27. k += i * j;
  28. printf("sig_int finished\n");
  29. }

当我们在执行10_9所示的程序的时候,按下终端字符来中断睡眠状态的进程,我们将得到如下的输出:

  1. [email protected]:~/UnixProgram/Chapter10$ ./10_9.exe
  2. ^C
  3. sig_int starting
  4. sleep2 returned:0
  5. [email protected]:~/UnixProgram/Chapter10$

我们可以看出sleep2中的longjmp函数会终止其他的信号处理函数sig_int,即是其他的信号处理函数还没有完成,如果你将SVR2的sleep函数与其他的信号处理函数混合使用的话,就会遇到这样的问题,详见练习10.3

sleep1与sleep2例子的目的是为了展示天真无邪地处理信号的过程中遇到的陷阱,接下来的章节将会接收避开上述问题的方法,因此你可以可靠地处理信号,并不需要与其他的代码段有干涉。

Example

对于函数alarm的常见的使用,除了sleep函数的实现之外,就是设置可能发生阻塞的操作的时间上限,举例来说,如果我们对一个可能引起阻塞的设备执行读取操作,我们想要read函数可以超时退出,在图10.10中的程序就是这样做的,从标准输入中读取一行输入,然后将其写出到一个标准输出中去。

  1. #include "apue.h"
  2. static void sig_alrm(int);
  3. int main(void)
  4. {
  5. int n;
  6. char line[MAXLINE];
  7. if(signal(SIGALRM, sig_alrm) == SIG_ERR)
  8. {
  9. err_sys("signal(SIGALRM) error");
  10. }
  11. alarm(10);
  12. if((n = read(STDIN_FILENO,line, MAXLINE)) < 0)
  13. {
  14. err_sys("read error");
  15. }
  16. alarm(0);
  17. write(STDOUT_FILENO, line, n);
  18. exit(0);
  19. }
  20. static void sig_alrm(int signo)
  21. {
  22. /*nothing to do,just return to interrupt the read*/
  23. }

Figure10.10 Calling read with a timeout

上述代码的处理序列在UNIX应用程序中是常见的,但是该应用程序有两个问题:

  1. 与图10.7中的例子相同的缺陷:在对函数alarm以及函数read的调用之间出现了一个竞态条件,如果进程在这两个函数的调用之间阻塞了进程,并且阻塞的时间超过了定时器时长,那么read函数就可能永远被阻塞了,许多这种类型的操作都会使用一个很长的定时器,比如说一分钟或者更长,使得上述情况的发生变得不太可能,然而无论如何,这仍然是一个竞态条件。
  2. 如果系统调用是自动重启的,那么read函数在SIGALRM信号处理函数返回以后并不会被中断,在这种情况下,超时将起不到任何作用。

在这个例子中,我们想要一个慢速的系统调用被中断,我们将在10.14中看到一种可移植的方法来实现上述功能。

Example

然我们再一次使用longjmp函数来实现上一个例子,使用这种方法,我们并不需要担心慢速系统调用是否能够被中断。

  1. include "apue.h"
  2. #include <setjmp.h>
  3. static void sig_alrm(int);
  4. static jmp_buf env_alrm;
  5. int main(void)
  6. {
  7. int n;
  8. char line[MAXLINE];
  9. if(signal(SIGALRM, sig_alrm) == SIG_ERR)
  10. {
  11. err_sys("signal(SIGALRM) error");
  12. }
  13. if(setjmp(env_alrm) != 0)
  14. err_quit("read timeout");
  15. alarm(10);
  16. if((n = read(STDIN_FILENO, line, MAXLINE)) < 0)
  17. {
  18. err_sys("read error");
  19. }
  20. alarm(0);
  21. write(STDOUT_FILENO, line, n);
  22. exit(0);
  23. }
  24. static void sig_alrm(int signo)
  25. {
  26. longjmp(env_alrm, 1);
  27. }

Figure 10.11 Calling read with a timeout, using longjmp.

这一版本能够按照预期的进行工作,无论系统是否会自动重启被中断的系统调用函数,注意,对于上述程序仍然有与其他信号发生冲突的问题。

如果我们想要对一个IO操作设置一个时间限制,我们需要使用函数longjmp,同时需要识别可能与其他信号处理函数发生的冲突。另一个选择是使用函数select或者是poll,这些内容将在14.4.1以及14.4.2中讲解。

来自为知笔记(Wiz)

时间: 2024-12-24 22:40:18

10.10 alarm以及pause函数的相关文章

1.信号处理之:kill(),alarm(),pause()函数

 1查看信号的方式:man 7 signal,通过这个命令可以查看到所有信息. 2查看信号kill -l 注意,后面的32个信号表示的实时信号. 会发现一个规律,前32种信号会有各种不同的名称,后32种会以"SIGRTMIN"或者"SIGRTMAX"开头,前者是从unix继承下来的信号,称为不可靠信号(也称为非实时信号),后者为了解决"不可靠信号"的问题进行了更改和扩充的信号形成了可靠信号(也称为实时信号) 如果想要了解可靠与不可靠信号,需要

10.6 可重入函数

当一个信号捕获到并开始被进程处理的时候,进程正常执行的指令序列将被信号处理函数临时中断,进程立即转到信号处理函数中开始执行,如果信号处理函数返回(而不是调用exit或者是longjmp等),然后在进入信号处理函数之前进程正在执行的指令序列将会接着执行,但是在信号处理函数中,我们无法获知在信号被捕获的时候进程正在执行那一段代码,如果进程正在使用函数malloc在其堆上分配额外的内存的过程中会发生什么呢?或者是进程正在调用一个函数的过程中,比如说getpwnam将会发生什么呢?函数getpwnam会

linux中alarm函数和pause函数详解实例

alarm(time);执行之后告诉内核,让内核在time秒时间之后向该进程发送一个定时信号,然后该进程捕获该信号并处理:pause()函数使该进程暂停让出CPU,但是该函数的暂停和前面的那个sleep函数的睡眠都是可被中断的睡眠,也就是说收到了中断信号之后再重新执行该进程的时候就直接执行pause()和sleep()函数之后的语句:下面是一个定时2秒的实例: /*******************************************************************

XCode6.3上使用opencv教程(MacOSX 10.10)

OpenCV 是一个基于(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows和Mac OS操作系统上.它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python.Ruby.MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法. 2. MacOSX上安装OpenCV 2.1. 安装Homebrew 2.2. 安装OpenCV 3. XCode建立OpenCV项目 3.1. 配置搜索路径 3.2. 添加链接库 3.3. 设置编译路径 3.

判断一个10*10的矩阵是否为单位矩阵

<C和指针>第8章编程练习第3题: 1 /* 2 ** 判断一个10*10的矩阵是否为单位矩阵 3 */ 4 5 #include <stdio.h> 6 #define ROW 10 7 #define COL 10 8 9 /* 10 ** 函数接受一个10*10的矩阵 11 ** 判断其是否为单位矩阵 12 ** 返回值: 13 ** 是单位矩阵,返回1 14 ** 不是单位矩阵,返回0 15 */ 16 int 17 indentity_matrix( int (*matr

mac x Yosemide(10.10) 下安装 jdk 1.7 (jdk 1.8)

注意: 双击jdk8后, 将 Java 8 Update 05.pkg包拖到Teminal中,可以获得正确的地址, 然后copy该地址替换下文对应的地址,空格等都不能出错.本人已经按照教程跌跌撞撞实验成功. mac x Yosemide(10.10) 下安装 jdk 1.7 (jdk 1.8) 在mac x yosemide 系统中不能正常更新jdk到1.7(1.8)的问题,会弹出上面的错误 提示.很多人就在这里会选择放弃他的jdk升级之旅,或者是还原他的mac系统 .其实没那么复杂.来看看我是

10.6 监控io性能 - 10.7 free命令 - 10.8 ps命令 - 10.9 查看网络状态 - 10.10 linux下抓包

- 10.6 监控io性能 - 10.7 free命令 - 10.8 ps命令 - 10.9 查看网络状态 - 10.10 linux下抓包 - 扩展tcp三次握手四次挥手 http://www.doc88.com/p-9913773324388.html  - tshark几个用法:http://www.aminglinux.com/bbs/thread-995-1-1.html  # 10.6 监控io性能 ![mark](http://oqxf7c508.bkt.clouddn.com/b

VMware Workstation11.0安装Mac OS X 10.10最完整指南(包含所需所有资源下载)

前言说明:最近换了新的电脑,配置好很多了,想装下虚拟机来玩下IOS,其中也遇到了几个大坑,现在刚完全装好,把所有步骤以及资源整合到一处,后面的朋友可以避免浪费很多无谓的百度时间. ""我先把使用到的程序以及版本说明下,因为这非常总要,使用虚拟机安装mac,其实就是装黑苹果,这要依赖很多破解工具,但这些工具都是有版本支持的.我这些版本装的没问题,但是你如果下载网上其他版本,我就不能确保一定没问题了,只能是自己试了."" VMware 11.0 永久不过期激活密钥 1F

Android基础入门教程——10.10 传感器专题(1)——相关介绍

Android基础入门教程--10.10 传感器专题(1)--相关介绍 标签(空格分隔): Android基础入门教程 1.传感器相关介绍: 说到传感器,相信大家都不会陌生吧,比如微信的摇一摇就用到了加速度传感器: 传感器的定义:一种物理设备或者生物器官,能够探测.感受外界的信号,物理条件(如光,热, 适度)或化学组成(如烟雾),并将探知的信息传递给其他的设备或者器官! 传感器的种类:可以从不同的角度对传感器进行划分,转换原理(传感器工作的基本物理或化学 效应):用途:输出信号以及制作材料和工艺