首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么usleep在启动时不能工作?

为什么usleep在启动时不能工作?
EN

Stack Overflow用户
提问于 2012-01-31 12:45:02
回答 2查看 883关注 0票数 0

我有一个守护进程,launchd在系统引导(OS )时运行。我需要将我的守护进程的启动延迟3-5秒,但以下代码在启动时立即执行,但在启动后适当延迟:

代码语言:javascript
复制
#include <unistd.h>
...
printf("Before delay\n");
unsigned int delay = 3000000;
while( (delay=usleep(delay)) > 0)
{
   ;
}
printf("After delay\n");

如果我在系统启动后手动运行它,它会正确地延迟。如果我让launchd在引导时启动它,控制台日志显示在延迟之前和延迟之后之间没有延迟-它们在同一秒内执行。

如果我能让launchd在引导后延迟一段时间后执行我的守护进程,那也没问题,但我的读数表明这是不可能的(也许我错了?)。

否则,我需要了解为什么我们的睡眠不能工作,我可以做些什么来修复它,或者我可以在启动过程的早期使用什么延迟来工作。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-01-31 12:58:21

首先要做的是。添加一些额外的代码来打印当前时间,而不是依靠launchd来完成。

标准输出的不同刷新行为可能正在发挥作用。

如果可以确定标准输出是交互式设备(例如从命令行运行它),则它是行缓冲的-您将在延迟之前刷新“之前”行。

否则,它是完全缓冲的,因此可能直到程序退出(或者达到4K的缓冲区大小)时才会发生刷新。这意味着launchd可能会看到线路一起出来,都是在延迟之后。

让C代码为这些行加上时间戳将告诉您这是否是问题所在,如下所示:

代码语言:javascript
复制
#include <stdio.h>
#include <time.h>
#include <unistd.h>

int main (void) {
    printf("%d: Before delay\n", time(0));
    unsigned int delay = 3000000;
    while( (delay=usleep(delay)) > 0);
    printf("%d: After delay\n", time(0));

    return 0;
}

要了解为什么缓冲可能是一个问题,请考虑运行上面的程序,如下所示:

代码语言:javascript
复制
pax> ./testprog | while read; do echo $(date): $REPLY; done
Tue Jan 31 12:59:24 WAST 2012: 1327985961: Before delay
Tue Jan 31 12:59:24 WAST 2012: 1327985964: After delay

您可以看到,因为缓冲使这两行在程序退出时出现在while循环中,所以它们得到的时间戳与12:59:24相同,尽管它们是在程序中相隔三秒生成的。

实际上,如果您按如下方式更改它:

代码语言:javascript
复制
pax> ./testprog | while read; do echo $(date) $REPLY; sleep 10 ; done
Tue Jan 31 13:03:17 WAST 2012 1327986194: Before delay
Tue Jan 31 13:03:27 WAST 2012 1327986197: After delay

您可以看到“周边”程序( while循环,或者在您的例子中是launchd)看到的时间与程序本身完全断开)。

其次,usleep是一个可能失败的函数!它可能会因为返回-1而失败,这个值远不大于零。

这意味着,如果它失败了,您的延迟实际上将是零。

usleepSingle UNIX Specification状态

在成功完成时,

()返回0。否则,它返回-1并设置errno以指示错误。

如果: EINVAL:指定的时间间隔大于或等于1,000,000微秒,则usleep()函数可能会失败。

你的代码肯定就是这种情况,尽管很难解释为什么它会在启动后而不是在启动之前工作。

有趣的是,Mac文档没有列出EINVAL,但如果睡眠被外部中断,它们确实允许EINTR。再说一遍,有些东西你应该检查一下。

您可以使用如下内容来检查这些可能性:

代码语言:javascript
复制
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>

int main (void) {
    printf("%d: Before delay\n", time(0));
    unsigned int delay = 3000000;
    while( (delay=usleep(delay)) > 0);
    printf("%d: After delay\n", time(0));
    printf("Delay became %d, errno is %d\n", delay, errno);
}

我刚刚注意到的另一件事是,从您的代码中,您似乎假设usleep返回未休眠(剩余)的微秒数,然后循环,直到完成所有操作,但手册页并没有证实这种行为。

我知道nanosleep可以做到这一点(通过更新传递的结构来包含剩余时间,而不是返回它),但usleep只返回0或-1。

sleep函数就是以这种方式工作的,它返回还剩的秒数。如果可能,您可能会考虑使用该函数。

在任何情况下,我仍然会运行上面的(最后)代码段,这样您就可以确定实际问题是什么。

票数 2
EN

Stack Overflow用户

发布于 2012-01-31 14:39:38

根据旧的POSIX.1标准,如OSX manual page中所述,usleep在成功时返回0,在错误时返回-1。

如果您得到一个错误,它很可能是EINTR (在OSX手册页面中记录的唯一错误),这意味着它被一个信号中断了。不过,你最好去errno上确认一下。作为附注,在Linux manual page上,它指出在某些情况下您也可以获得EINVAL

usec不小于1000000。(在被认为是错误的系统上。)

作为另一个附注,为了支持nanosleep,在最新的POSIX.1标准中已经注意到了usleep

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9074515

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档