2010-11-20 72 views
3

所以情況就是這樣。我有一個C++庫,它正在進行一些進程間通信,使用wait()函數來阻塞和等待傳入的消息。難點是我需要定時等待,如果在指定的時間內沒有收到消息,它將返回一個狀態值。如何在阻塞呼叫周圍實現定時等待?

最優雅的解決方案可能是重寫庫來爲其API添加定時等待,但爲了這個問題,我認爲這是不可行的。 (實際上,這看起來很困難,所以我想知道其他的選項是什麼。)

這是我怎麼會做這樣一個忙等循環,在僞代碼:

while(message == false && current_time - start_time < timeout) 
{ 
    if (Listener.new_message()) then message = true; 
} 

我不盡管如此,你還是需要忙於等待處理器週期。而且我也不想僅在循環中添加sleep()調用以避免處理器負載,因爲這意味着響應速度較慢。我想要一些適當的塊和中斷。如果更好的解決方案涉及線程(這似乎很可能),我們已經使用boost::thread,所以我寧願使用它。

我發佈這個問題,因爲這似乎是一種明確的「最佳實踐」正確的答案,因爲這是一種很常見的模式。什麼是正確的做法?

編輯補充:我的很大一部分關注點在於,程序中的這一點對性能至關重要,並且對於避免競爭條件或內存泄漏至關重要。因此,雖然「使用兩個線程和一個計時器」是有益的建議,但我仍然試圖找出如何以一種安全和正確的方式實際實現它,並且我可以很容易地看到自己在代碼中犯下新手的錯誤,甚至不知道我做了什麼。因此,一些實際的示例代碼將非常感謝!另外,我對多線程解決方案有所擔憂:如果我使用「在第二個線程中放置阻塞調用並在該線程上執行定時等待」方法,那麼第二個線程會發生什麼阻止呼叫永不返回?我知道在第一個線程中的等待時間會返回,我會看到沒有答案發生並繼續進行,但是我是否已經「泄漏」了一個將永遠處於阻塞狀態的線程?有什麼辦法可以避免這種情況? (有什麼辦法可以避免這種情況,避免泄漏第二個線程的內存?)如果阻塞調用沒有返回,我需要的完整解決方案需要避免發生泄漏。

回答

1

您可以使用sigaction(2)alarm(2),它們都是POSIX。您使用sigaction爲超時設置回調動作,然後使用鬧鈴設置一個計時器,然後進行阻止呼叫。如果阻塞呼叫在您選擇的超時時間內未完成,則會中斷呼叫(以秒爲單位;如果您需要更精細的粒度,則可以使用setitimer(2))。

請注意,C語言中的信號有點多毛,並且在信號處理程序中可以做的事情有相當繁重的限制。

本頁面是有用的,相當簡潔: http://www.gnu.org/s/libc/manual/html_node/Setting-an-Alarm.html

+0

謝謝!我想這聽起來像我想要的 - 但我沒有足夠的細節來了解如何去做。特別是,我不知道如何正確設置一個信號來中斷阻塞調用並永久停止它,而不是在中斷處理程序退出後再回到它。你能否就如何做到這一點添加一些解釋? – 2010-11-20 21:03:25

+1

從我的答案中的GNU鏈接:「爲了能夠使用鬧鐘功能來中斷可能無限期阻塞的系統調用,使用sigaction註冊信號處理程序時不要設置SA_RESTART標誌很重要。我會嘗試。那麼問題是當它的基本操作返回EINTR時,庫代碼會做什麼。如果幸運的話,你正在使用的庫會有某種你可以從你的信號處理程序調用的「停止」函數,或者它只會從EINTR上的阻塞調用中返回。如果它更持久並且在EINTR上再次阻止,生活就會更加困難。 – 2010-11-21 16:52:04

+0

好的,這開始有意義 - 我錯過了那條線,也沒有意識到SA_RESTART存在,或者中斷的代碼可能發生任何事情,除了它繼續停止的地方。感謝您指出了這一點! (我不確定在這種情況下庫代碼的作用,或者我們可以在多大程度上依賴它,因爲它有鉤子讓人們爲不同的通信庫添加不同的代碼,但我會發現的。) – 2010-11-22 21:43:03

1

你想要的是類似select(2),這取決於你的目標操作系統。

+0

喜歡的東西,是的。這似乎是特定於文件描述符,雖然這是與任意庫調用。根據我使用的版本,它可能會或可能不會使用深層文件描述符,但我無法訪問它們。不過謝謝! – 2010-11-20 20:54:57

1

這聽起來像你需要一個'監視器',能夠通過共享互斥量(通常)向線程通知資源的可用性。在Boost.Thread condition_variable可以完成這項工作。

1

你可能想看看timed locks:你的阻塞方法可以在開始等待數據可用之前等待並釋放鎖。然後,您可以嘗試在您的定時等待方法中獲取鎖定(超時)。

1

將封鎖調用封裝在單獨的線程中。在該線程中有一箇中間消息緩衝區,由條件變量保護(如前所述)。讓主線程定時 - 等待該條件變量。如果條件滿足,則接收中間存儲的消息。

因此,基本上在API和您的應用程序之間放置了一個能夠定時等待的新層。適配器模式。

+0

不錯,但是如果這個阻止呼叫不會解除阻塞,那麼我的單獨線程會發生什麼?如果我在連續運行的程序中每分鐘執行一次該怎麼辦? – 2010-12-16 06:51:28