2011-09-28 57 views
7

我看到有人在與我一起工作的大量多線程,多進程應用程序系統的某些部分執行此操作。它似乎是圍繞調試線:在UNIX系統上調用睡眠(0)的效果是什麼?

std::cerr << "DEBUG: Reaching: " << __FUNCTION__ << " @ " << __LINE__ << std::endl; 
sleep(0); 

如果我宏出睡眠(0); (即將其更改爲「」),系統的調試輸出似乎以不同的順序排列(不太可預測),所以我認爲它會使線更早出現 - 但我認爲std :: cerr是無緩衝的,而std: :無論如何,endl調用std :: flush(),那爲什麼會這樣?

+0

我正要告訴你閱讀手冊頁,但是我先閱讀了它,並沒有回答這個問題。 –

+1

窮人的pthread_yield? – Nemo

+1

@Nemo,差不多。這實際上是整個重量級過程的產量;控制權返回到進程調度程序。 –

回答

12

基本上,它將控制權交給調度程序,並讓您可以立即重新調度。這就是說,試圖欺騙操作系統做一些事情基本上是一種破解。

而愚弄操作系統永遠不是一個好主意。

如果系統適當負載不足,那麼進入睡眠將意味着操作系統得到控制並讓I/O隊列刷新,所以它會產生這種效果。有時。根據。

究竟它在做什麼取決於實施細節,坦率地說,你不能依賴。

0

您可以使用此方法讓其他進程運行,這可能會等待一些cpu時間,但是如果沒有其他進程正在等待運行,則不會強制執行特定的延遲。

8

它以難以預測的方式干擾調度器。

通常,結果將類似於撥打pthread_yield() - 您放棄時間片。這樣做的結果是,在大量調試打印負載下,在寫入cerr的過程中(例如,在那些<<之間),您將不太可能被搶佔,因爲您將在時間片的開頭最後一個調試打印,因此你不太可能有多個線程覆蓋對方的輸出(即得到類似DEBUG: REACHING: foo() @ DEBUG: REACHING bar()17 @ 24的東西)。

這就是說,這種方法是不可靠的 - 它擾亂了調度器,而不是要求特定的語義。它也很慢 - 無條件地進入內核產生(並且可能頻繁地在多個線程之間彈跳控制)。在多核CPU上正常工作的可能性較小。

將像這樣的所有調試輸出置於互斥體上會更好。也就是說,由於這是調試代碼,因此作者可能使用了一種快速而骯髒的破解工具來讓它工作以調試他們遇到的任何問題並不奇怪。

1

在大多數平臺上,sleep(0)會導致調度程序對當前線程進行或多或少的處理,就好像它已經用完了它的時間片。通常這意味着,如果可能的話,同一進程中的另一個線程將安排在該內核中(如果可以運行的話)。正如你所指出的那樣,它往往會使調度更具可預測性。對我來說,這在調試時看起來適得其反。

我同意尼莫的評論,它與pthread_yield大致相同。它確實有一些合法用途,但它有時被錯誤地用作提供更公平性或減少延遲的方式。通常它會使性能變得更糟,因爲上下文切換會吹出緩存。

我看了其他答案,我同意一般的迷茫感。我敢打賭,除了有人認爲更可預測的時間安排是件好事之外,沒有什麼好的理由。 (不是這樣,靈活性好,對調度器的要求越多,爲了滿足這些要求就犧牲得越多,如果實施的要求不是實際要求的話,那麼你就不用交換性能。)

0

正如其他人所說,sleep(0)是一個系統調用,導致當前線程放棄對CPU的控制。

我能想到的唯一正當理由是使用LOCK(x86)等彙編指令來實現自己的同步原語,例如自旋鎖; LDREX和STREX(ARMv7)。在這種情況下,如果我們遇到鎖,我們不妨立即放棄控制,希望另一個線程能夠完成它的工作並解鎖我們的鎖。在我們的時間片結束之前,這絕對是在旋轉。

話雖如此,在實現自己的同步原語時,您確實需要知道自己在做什麼。具體而言,您可能需要放入內存屏障來強制執行讀取和寫入操作。使用平臺上提供的原語可能會更好。