sleep函数

sleep函数

我们已经在例子中使用了很多次sleep函数,并在Figures10.7和10.8中显示了两个缺陷。

#include <unistd.h>

unsigned int sleep(unsigned int seconds);

Returns: 0 or number of unslept seconds

这个函数引发调用的进程被挂起,直到:

  1. seconds指定的时间逾期。
  2. 一个信号被进程捕获并且信号处理函数返回。

使用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);
}

发表回复