我有一个守护进程,launchd在系统引导(OS )时运行。我需要将我的守护进程的启动延迟3-5秒,但以下代码在启动时立即执行,但在启动后适当延迟:
#include <unistd.h>
...
printf("Before delay\n");
unsigned int delay = 3000000;
while( (delay=usleep(delay)) > 0)
{
;
}
printf("After delay\n");如果我在系统启动后手动运行它,它会正确地延迟。如果我让launchd在引导时启动它,控制台日志显示在延迟之前和延迟之后之间没有延迟-它们在同一秒内执行。
如果我能让launchd在引导后延迟一段时间后执行我的守护进程,那也没问题,但我的读数表明这是不可能的(也许我错了?)。
否则,我需要了解为什么我们的睡眠不能工作,我可以做些什么来修复它,或者我可以在启动过程的早期使用什么延迟来工作。
发布于 2012-01-31 12:58:21
首先要做的是。添加一些额外的代码来打印当前时间,而不是依靠launchd来完成。
标准输出的不同刷新行为可能正在发挥作用。
如果可以确定标准输出是交互式设备(例如从命令行运行它),则它是行缓冲的-您将在延迟之前刷新“之前”行。
否则,它是完全缓冲的,因此可能直到程序退出(或者达到4K的缓冲区大小)时才会发生刷新。这意味着launchd可能会看到线路一起出来,都是在延迟之后。
让C代码为这些行加上时间戳将告诉您这是否是问题所在,如下所示:
#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;
}要了解为什么缓冲可能是一个问题,请考虑运行上面的程序,如下所示:
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相同,尽管它们是在程序中相隔三秒生成的。
实际上,如果您按如下方式更改它:
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而失败,这个值远不大于零。
这意味着,如果它失败了,您的延迟实际上将是零。
usleep的Single UNIX Specification状态
在成功完成时,
()返回0。否则,它返回-1并设置errno以指示错误。
如果: EINVAL:指定的时间间隔大于或等于1,000,000微秒,则usleep()函数可能会失败。
你的代码肯定就是这种情况,尽管很难解释为什么它会在启动后而不是在启动之前工作。
有趣的是,Mac文档没有列出EINVAL,但如果睡眠被外部中断,它们确实允许EINTR。再说一遍,有些东西你应该检查一下。
您可以使用如下内容来检查这些可能性:
#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函数就是以这种方式工作的,它返回还剩的秒数。如果可能,您可能会考虑使用该函数。
在任何情况下,我仍然会运行上面的(最后)代码段,这样您就可以确定实际问题是什么。
发布于 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。
https://stackoverflow.com/questions/9074515
复制相似问题