sleep函数
我们已经在例子中使用了很多次sleep函数,并在Figures10.7和10.8中显示了两个缺陷。
|
这个函数引发调用的进程被挂起,直到:
- seconds指定的时间逾期。
- 一个信号被进程捕获并且信号处理函数返回。
使用alarm信号,因为其它进程的活动,实际返回时间可能要比需求的时间要长一些。
第一种情况函数返回0。当sleep早于预定时间时,时因为某些信号被捕获(第二种情况),返回的值是剩余的秒数。
虽然sleep能被alarm函数实现(APUE10.10节),但这不是必须的。如果使用了alarm,那么这两个函数会相互干扰。(If alarm is used, however, there can be interactions between the two functions.)POSIX.1标准不包含所有未指定的相互作用。(The POSIX.1 standard leaves all these interactions unspecified.)例如,如果我们执行alarm(10)后3秒种执行sleep(5),会发生什么?sleep会返回5秒(假设与此同时没有其它信号被捕获),但是两秒后会有其他的SIGALRM信号产生么?这依赖于具体实现。
【Solaris 9使用alarm实现sleep。Solaris的手册描述sleep说:之前计划的alarm被适当处理。例如,拿刚才那个例子来说,在sleep返回前,它将会重新不熟alarm在2秒后发生;sleep返回0。(明显,sleep必须保存SIGALRM的信号处理函数的地址并且在运行前重置它。)同样,如果执行alarm(6)之后等待3秒后执行sleep(5),sleep3秒后返回(当alarm关闭时),而不是5秒后返回。这里,sleeep返回2(未使用的时间)。
FreeBSD 5.2.1, Linux 2.4.22和Mac OS X 10.3,换句话说,使用其它技术的:由nanosleep(2)函数延迟。这个函数在Single UNIX Specification中实时扩展,它有很高的精度。(This function is specified to be a high-resolution delay by the real-time extensions in the Single UNIX Specification.)这个函数允许sleep的实现信号独立。(This function allows the implementation of sleep to be independent of signals.)
为了移植,你不应该做任何关于sleep实现的假设,但是如果你有任何混合使用sleep和其它时间函数的想法,你需要知道它们之间的相互作用。】
例子
Figure10.29显示了POSIX.1的sleep函数实现。这个函数是Figure10.7的一个修改版本,它能可靠的处理信号,避免早期版本中的竞争条件。我们仍然没有处理之前设置alarm和sleep之间的干扰问题。(就像我们提到的,这些互扰问题没有被POSIX.1定义。)
这比之前Figure10.7的代码要多。我们不使用任何非本地跳转的形式(就像Figure10.8中那样,去避免alarm和pause之间的竞争条件。),所以在这里当SIGALRM的信号处理函数正在执行时并不会被影响到。
Figure 10.29. Reliable implementation of sleep#include "apue.h"
static void
sig_alrm(int signo)
{
/* nothing to do, just returning wakes up sigsuspend() */
}
unsigned int
sleep(unsigned int nsecs)
{
struct sigaction newact, oldact;
sigset_t newmask, oldmask, suspmask;
unsigned int unslept;
/* set our handler, save previous information */
newact.sa_handler = sig_alrm;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGALRM, &newact, &oldact);
/* block SIGALRM and save current signal mask */
sigemptyset(&newmask);
sigaddset(&newmask, SIGALRM);
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
alarm(nsecs);
suspmask = oldmask;
sigdelset(&suspmask, SIGALRM); /* make sure SIGALRM isn't blocked */
sigsuspend(&suspmask); /* wait for any signal to be caught */
/* some signal has been caught, SIGALRM is now blocked */
unslept = alarm(0);
sigaction(SIGALRM, &oldact, NULL); /* reset previous action */
/* reset signal mask, which unblocks SIGALRM */
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return(unslept);
}
|