2009-05-18 26 views
25

不幸的是,我需要調用一個庫函數,它有時不會在給定的時間內終止。有沒有辦法調用該函數,但如果它不在n秒內終止,則中止它?C++:如何實現任意函數調用的超時?

我不能修改函數,所以我不能直接放入中止條件。我必須添加一個超時功能外部

這可能是一個可能的解決方案,將其作爲(boost)線程啓動,然後我可以在一段時間後終止?會有那樣的工作嗎?我其實是相信功能是不是線程安全,但是如果我將它作爲只有單線程運行它並不重要,對吧?還有其他(更好的)解決方案嗎?

+0

庫函數是做什麼的? – peterchen 2009-05-19 13:02:52

+0

Uuh,計算一些東西......科學計算實際上不會在某些條件下終止。 – Frank 2009-05-19 23:57:31

回答

18

你可以生成一個boost::thread調用API:

boost::thread api_caller(::api_function, arg1, arg2); 
if (api_caller.timed_join(boost::posix_time::milliseconds(500))) 
{ 
    // API call returned within 500ms 
} 
else 
{ 
    // API call timed out 
} 

升壓不允許你殺工作線程,雖然。在這個例子中,它只是孤兒。

您必須小心該API調用的功能,因爲它可能永遠不會釋放它所獲取的資源。

8

你在說什麼通常稱爲「看門狗」系統。看門狗通常是第二個線程,用於檢查所有其他線程的狀態。看門狗通常設置爲定期運行。如果沒有收到來自其他線程的響應,那麼看門狗可以通知用戶,或者甚至在可能的情況下安全地取消違規線程(取決於您的應用程序)。

+4

根據庫函數的作用,殺死沒有響應的線程可能非常不安全。一種安全的方法是將任務分派到單獨的過程。 – 2009-05-18 21:27:53

+0

如何開始這樣一個單獨的過程?我的應用程序可以傳遞一些數據(並返回一些結果數據)而不通過文件系統嗎? – Frank 2009-05-18 21:48:43

+1

這是有點複雜,特定於平臺 - 可能很容易成爲一個單獨的stackoverflow問題,我想。有幾種方法可以在進程之間傳遞數據。這稱爲IPC(進程間通信),也是平臺特定的。 – 2009-05-18 21:56:21

3

線程的問題是一些資源在線程終止後將無法釋放。如果你沒有獲得你必須釋放的資源,那麼就使用線程。

14

我認爲完成此操作的唯一安全方法是產生一個獨立的沙箱進程,該進程將庫函數作爲應用程序的代理進行調用。您需要在應用程序和代理之間實現某種類型的IPC。在閱讀IPC回覆時實現超時是相當平凡的。如果讀取由於超時而失敗,則可以安全地終止代理,而不會危及應用程序的健康。

1

你需要的是一個線程和一個可以保存函數調用結果的Future Object

對於使用boost的示例,請參見here

您需要在超時後檢查未來,如果未設置,請按照相應的步驟操作。

3

的問題是,與進程解決方案不支持的功能你最終可能無效的狀態。

示例:當內存分配發生時終止線程時,您的進程堆可能已損壞。

因此,您可能會終止通話,但您也必須終止處理。在很多情況下,破壞性副作用的可能性很小,但我不會在這方面打賭我的計算。

就像本·斯特勞布所說的,你可以孤立地把它放在最低優先級上,讓它跑向無窮大。這當然只是一個有限的解決方案:如果線程消耗資源(可能),它們將減慢系統速度,並且每個進程的線程數也有限制(通常是由於線程堆棧的地址空間)。

通常,我更喜歡外部處理解決方案。一個簡單的模式是這樣的:
將輸入數據寫入文件,使用文件作爲參數啓動外部進程。外部進程將進程(如果有)寫入可監控的磁盤文件,甚至可以允許進程從啓動的位置恢復。結果被寫入磁盤,並且父進程可以讀取它們。

當您終止進程時,您仍然必須處理同步對外部資源(如文件)的訪問,以及如何處理被遺棄的重複文件等。但它通常是一個強大的解決方案。

1

使用孤立進程,啓動它並計時執行。如果耗盡時間,請調用操作系統來殺死它。

如何避免種族conds。在這種模式下:

  • 創建一個文件存儲在參數(當然,一切都是作爲VAL傳遞)。 孤兒進程只允許從這個文件讀取數據。

  • 孤兒進程輸入數據,創建一個結果值的輸出文件並關閉它。

  • 只有當一切都完成,孤兒刪除輸入文件,這是一個事實,表明主進程工作已完成。

這避免了閱讀半寫入的文件的問題,由於主第一次注意到由於缺少輸入文件,用於讀取輸出文件,該文件確實完成開(因爲在之前刪除輸入關閉,操作系統調用堆棧是順序的)。

1

「我需要調用一個庫函數,有時不會在給定的時間內終止,不幸的是,有沒有辦法調用該函數,但是如果它在n秒內沒有終止,就會中止它?

簡短的回答是否定的。這通常是麻煩的...調用本身必須在某個時間終止(實現它自己的超時),但是阻塞調用通常是麻煩的(例如gethostbyname()),因爲那麼它將取決於它們(或系統)的超時,而不是你的。

因此,只要有可能,儘量使線程中運行的代碼在必要時乾淨地退出 - 代碼本身必須檢測並處理錯誤。它可以發送消息和/或設置狀態,以便主(或另一個)線程知道發生了什麼。

個人喜好,在高度可用的系統中,我喜歡我的線程經常旋轉(儘管沒有忙鎖定),具有特定的超時,調用非阻塞函數,並且具有精確的退出條件。全局或特定於線程的「完成」變量爲乾淨退出提供了技巧。