第十章*信号(十九)--sleep函数

我们已经在本文许多例子里使用了sleep函数,并在10.10节给出两个有缺陷的实现。



  1. #include <unistd.h>

  2. unsigned int sleep(unsigned int seconds);

  3. 返回0或未睡眠的秒数。


这个函数导致调用进程被挂起,直到下面某种情况发生:


1、seconds指定的挂钟时间量已经逝去;


2、进程捕获一个信号而信号处理器返回。


和alarm信号一样,真实的返回可能比所请求的更晚,因为其它系统活动。


在第一种情况,返回值为0。当sleep因为信号被捕获(第二种情况)而更早返回时,返回值是未睡眠的秒数(请求的时间减去真实睡眠的时间)。


尽 管sleep可以用alarm函数实现(10.10节),但是这并不是必需的。如果alarm被使用,在这两个函数之间可能会有交互。POSIX.1标准 没有规定这些交互。例如,如果我们执行一个alarm(10)并在3秒挂钟时间后执行一个sleep(5),会发生什么呢?sleep会在5秒返回(假定 这时没有其它信号被捕获),但是另一个SIGALRM信号会在2秒后产生吗?这些细节取决于实现。


Solaris 9用alarm实现sleep。Solaris sleep手册页说前一个调度好的闹钟被恰当处理。例如,在前一个场景里,在sleep返回前,它将重新调度闹钟,使它在2秒后发生;sleep在这种情 况下返回0。(显然,sleep必须为SIGALRM保存信号处理器的地址并在返回前重置它。)还有,如果我们执行一个alarm(6)而3秒后执行一个 sleep(5),sleep在3秒后返回(此时闹钟到时),而不是5秒后。这里,sleep的返回值是2(未睡眠的秒数)。


另一方面,FreeBSD、Linux、Mac OS X使用另一种技术:延迟由nanosleep提供。这个函数被规定为高精度的延迟,由SUS的实现扩展提供。这个函数允许sleep的实现与信号无关。


为了可移植性,你不应该对sleep的实现作任何假设,但是如果你有sleep调用和任何其它计时函数相混的任何意图,则你必须小心可能的交互。


下面的代码展示了POSIX.1 sleep函数的一个实现。这个函数是10.10节里的一个修改,它可靠地处理信号,避免早先实现的竞争条件。我们仍然不处理任何与之前设置的闹钟之间的交互。(正如我们提到的,这些交互没有定义在POSIX.1里。)



  1. #include <signal.h>

  2. static void
  3. sig_alrm(int signo)
  4. {
  5.     /* nothing to do, just returning wakes up sigsuspend() */
  6. }

  7. unsigned int
  8. sleep(unsigned int nsecs)
  9. {
  10.     struct sigaction newact, oldact;
  11.     sigset_t newmask, oldmask, suspmask;
  12.     unsigned int unslept;

  13.     /* set our handler, save previous information */
  14.     newact.sa_handler = sig_alrm;
  15.     sigemptyset(&newact.sa_mask);
  16.     newact.sa_flags = 0;
  17.     sigaction(SIGALRM, &newact, &oldact);

  18.     /* block SIGALRM and save current signal mask */
  19.     sigemptyset(&newmask);
  20.     sigaddset(&newmask, SIGALRM);
  21.     sigprocmask(SIG_BLOCK, &newmask, &oldmask);

  22.     alarm(nsecs);

  23.     suspmask = oldmask;
  24.     sigdelset(&suspmask, SIGALRM); /* make sure SIGALRM isn't blocked */
  25.     sigsuspend(&suspmask); /* wait for any signal to be caught */

  26.     /* some signal has been caught, SIGALRM is now blocked */

  27.     unslept = alarm(0);
  28.     sigaction(SIGALRM, &oldact, NULL); /* reset previous action */

  29.     /* reset signal mask, which unblocks SIGALRM */
  30.     sigprocmask(SIG_SETMASK, &oldmask, NULL);
  31.     return(unslept);
  32. }


要写这个可靠的实现比早先要花费更多的代码。我们不使用任何形式的非本地分支(之前我们用它来避免alarm和pause之间发生的竞争条件),所以对其它当SIGALRM被处理时可能正执行的信号处理器没有效果。
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(245) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zheguangqi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值