第一件事。放入一些额外的代码也可以打印出当前时间,而不是依赖于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 而失败,该值远不大于零。
这意味着,如果它失败了,你的延迟实际上将一事无成。
单一 UNIX 规范指出,对于usleep
:
成功完成后,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
函数以这种方式运行,返回尚未结束的秒数。如果可能的话,也许您可能会考虑使用该功能。
无论如何,我仍然会运行上面的(最后一个)代码段,以便您确定实际问题是什么。