我有一个守护进程launchd
在系统启动时运行(OS X)。我需要将我的守护程序的启动延迟3-5秒,但是下面的代码在启动时立即执行,但在启动后正常延迟:
#include <unistd.h>
...
printf("Before delay\n");
unsigned int delay = 3000000;
while( (delay=usleep(delay)) > 0)
{
;
}
printf("After delay\n");
如果我在系统启动后手动运行它,它会正确延迟。如果我让launchd
在启动时启动它,控制台日志显示在延迟之前和延迟之后没有延迟 - 它们在同一秒内执行。
如果我可以在启动后延迟一段时间后让launchd
执行我的守护进程也没关系,但是我的阅读表明这是不可能的(也许我错了?)。
否则,我需要理解为什么usleep不起作用,我可以做些什么来解决它,或者我可以使用什么延迟而不是在启动过程的早期工作。
答案 0 :(得分:2)
首先要做的事情。添加一些额外的代码以打印当前时间,而不是依靠launchd
来执行此操作。
标准输出的不同冲洗行为可能会发挥作用。
如果可以确定标准输出是交互式设备(例如从命令行运行它),则 line 缓冲 - 您将在延迟之前刷新“之前”行
否则,它是完全缓冲的,因此在程序退出之前(或者达到(例如)4K的缓冲区大小时,可能不会发生刷新。这意味着launchd
可能会看到线条一起出现,两者< em>延迟之后。
获取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
的{{3}}州:
成功完成后,usleep()返回0.否则,返回-1并设置errno以指示错误。
如果出现以下情况,则usleep()函数可能会失败:[EINVAL]:指定1,000,000或更多微秒的时间间隔。
你的代码肯定是这种情况,虽然很难解释为什么它在启动之后工作,而不是之前。
有趣的是,Mac OSX文档没有列出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
函数以这种方式起作用,返回尚未开始的秒数。如果可能的话,也许您可能会考虑使用该功能。
在任何情况下,我仍会运行上面的(最后一个)代码段,以便您可以确定实际问题是什么。
答案 1 :(得分:1)
根据旧的POSIX.1标准,并且如OSX manual page中所述,usleep
成功时返回0,错误时返回-1。
如果您收到错误,则最有可能是EINTR
(OSX手册页中记录的唯一错误),这意味着它已被信号中断。你最好检查一下errno
是否确定。作为旁注,在Linux manual page上,它表明在某些情况下您也可以获得EINVAL
:
usec不小于1000000.(在被认为是错误的系统上。)
另一方面,usleep
已在最新的POSIX.1标准中被使用,有利于nanosleep
。