2012-01-31 101 views
0

我有一個守護進程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

你想通過延遲代碼執行來實現什麼? – Costique 2012-01-31 04:51:31

+0

@Costique我在等待各種服務不僅可用,而且還執行了一些我無法測試的具體操作。此外,這個守護進程必須通過雪豹在老虎上運行,並且每種情況下的服務都略有不同 - 我想避免添加額外的代碼來檢查平臺。簡單的延遲可能被認爲是破解,但它是一個優雅的延遲,它可以解決我在所有平臺上的問題,而不會影響程序的整體運行。 – 2012-01-31 06:01:40

回答

2

第一件事是第一件事。把一些額外的代碼也打印出當前時間,而不是依靠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 

可以看到的是,因爲緩衝導致兩個線當程序退出,他們得到的12:59:24的同一時刻,儘管他們產生相距三秒鐘程序中的事實出現在while循環。

事實上,如果你改變它,如下所示:

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,這是非常不大於零而失敗。

這意味着,如果它失敗了,你的延遲就沒有效果。

Single UNIX Specification狀態,爲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); 
} 

還有一件事我剛剛注意到,從你的代碼中似乎假設微秒unslept的usleep收益數量(剩餘),然後循環直到全部完成,但該行爲不會被手冊頁承載。

我知道nanosleep這樣做(通過更新傳遞的結構來包含剩餘時間而不是返回它),但usleep只返回0或-1。

sleep函數以這種方式工作,返回秒數。如果可能的話,也許你可以考慮使用這個函數。

在任何情況下,我仍然會運行上面的(上一個)代碼段,以便確定實際問題是什麼

+0

好的一點,但是在這種情況下很明顯 - 我增加了60秒的延遲時間來測試它,而且應用程序在啓動後60秒之前確實運行得很好。 – 2012-01-31 06:02:23

+0

@Adam,你應該從C運行時獲得確認它的時間,然後發佈結果。另外,我添加了可能會讓睡眠失敗,你應該檢查的其他東西。 – paxdiablo 2012-01-31 06:21:27

+0

事實證明,除了使用不正確的睡眠方式之外,還有緩衝問題和另一個無關的問題,但是這些問題會影響延遲的進展。感謝您的輸入 - 您將獲得選定的答案,當然,額外的調試輸出將我推向了正確的解決方案。 – 2012-02-01 15:43:30

1

根據舊的POSIX.1標準,並且如OSX manual page中所述,usleep在成功時返回0,在出錯時返回-1。

如果出現錯誤,很可能是EINTR(OSX手冊頁中記錄的唯一錯誤),表示它已被信號中斷。你最好檢查errno是肯定的。作爲一個側面說明,在Linux manual page它指出,可以在某些情況下得到EINVAL太:(。在系統中被認爲是一個錯誤)

微秒不低於100萬小

另一方面,usleep在最新的POSIX.1標準中已被引用,贊成nanosleep