2008-11-07 47 views
20

我在寫一個應用程序,它阻止來自兩個istreams的輸入。殺死阻塞的Boost ::線程

istream讀取的是一個同步(阻塞)調用,所以我決定創建兩個Boost::thread來完成讀取。

這些線程中的任何一個都可以到達「結束」(根據收到的某些輸入),一旦達到「結束」,兩個輸入流都會停止接收。不幸的是,我不知道哪個會這樣做。

因此,我不能在兩個線程上都使用join(),因爲只有一個線程(不能預先確定哪一個)會實際返回(取消阻塞)。

我必須以某種方式迫使另一個退出,但它被阻止等待輸入,所以它不能自己決定是時候返回(條件變量或不是)。

是他們的一種方式之一:

  • 發送信號,一個boost ::線程,或
  • istream爲 「失敗」,或
  • 殺死一升壓::主題?

注:

  • 其中istreams的是cin
  • 我試圖重新啓動的過程中,所以我不能關閉,禁止他們正在重置的方式輸入流。

編輯:

  • 達到了「結束」時,我知道,我知道哪個線程已成功完成,並需要被殺害。我需要弄清楚它的殺戮(或者從一個istream中讀取不同的策略)。
  • 我需要兩個線程退出並清理正確:(

謝謝!

回答

4

我不認爲有辦法做到這一點的跨平臺的,但pthread_cancel可以應該是你在找什麼隨着升壓線程你可以從一個線程獲得native_handle,並呼籲它pthread_cancel可以。

另外一個更好的辦法可能是使用升壓asio等於多個文件選擇調用的。這樣一個線程被阻塞等待輸入,但它可能來自任何一個輸入str EAM。但我不知道用iostreams做這種事情有多容易。

+0

幸運的是,我現在正在爲linux機器開發,但更喜歡便攜式版本。感謝你! – mmocny 2008-11-07 17:13:31

+0

pthread_cancel()在類似的情況下沒有爲我設置它,甚至不把它的取消類型設置爲ASYNCHRONOUS。 – gatopeich 2011-03-21 12:24:19

0

而不是試圖殺死你的線程,你總是可以嘗試加入線程,而不是,如果失敗,你加入另一個。 (假設你將永遠能夠加入你的兩個線程中的至少一個)。

提升:線程您正在尋找timed_join函數。

但是,如果您想查看正確的答案,那就是使用具有定時等待的非阻塞io。允許您獲得異步io的非阻塞同步io的流結構。

你說的是讀一個istream,但一個istream只是一個接口。對於標準輸入,你可以忽略標準輸入文件描述符來中斷讀取。至於另一個,它取決於您正在閱讀的位置...

+0

有關如何做到這一點的任何建議?我的印象是不可能的(可以輕易地做到這一點)與cin。我已經提到我正在加入一個線程,而另一個線程則是我需要處理的。不過謝謝。 – mmocny 2008-11-07 17:19:13

0

在Windows下,使用QueueUserAPC排隊引發異常的proc。這種方法適用於我。

但是:我剛剛發現boost mutex等在win32上不是「可警告的」,所以QueueUserAPC不能中斷它們。

1

在linux上,我使用pthread_signal(SIGUSR1),因爲它會中斷阻塞IO。在移植我的代碼時,我沒有發現窗口上有這樣的調用。在套接字閱讀調用中只有一個已棄用的。在Windows中,您必須明確定義一個會中斷您的阻止呼叫的事件。所以沒有這樣的東西(AFAIK)作爲中斷阻塞IO的通用方法。

boost.thread設計通過管理良好識別的中斷點來處理此問題。我不太瞭解boost.asio,看起來你不想依賴它。如果你不想重構使用非阻塞範例,你可以做的是在非阻塞(輪詢)和阻塞IO之間使用一些東西。這是做類似的信息(僞代碼):

while(!stopped && !interrupted) 
{ 
    io.blockingCall(timeout); 
    if(!stopped && !interrupted) 
    { 
     doSomething(); 
    } 
} 

然後你打斷你的兩個線程,並加入他們的行列......

也許正是你的情況更簡單?如果你有一個知道一個線程結束的主線程,你只需要關閉另一個線程的IO呢?

編輯: 通過我感興趣的是你的最終解決方案的方式......

0

看來,線程不幫你做,你以簡單的方式想要什麼。如果Boost.Asio不符合您的喜好,請考慮使用select()

這個想法是得到兩個文件描述符,並使用select()來告訴你哪些輸入可用。 cin的文件描述符通常爲STDIN_FILENO;如何獲得另一個取決於你的具體情況(如果它是一個文件,只需open()而不是使用ifstream)。

在循環中調用select()以找出要讀取哪個輸入,以及何時停止,只是跳出循環。

4

是的!

boost::thread::terminate()將完成您的規格工作。

這將導致目標線程拋出異常。假設它沒有被捕獲,堆棧將正確地銷燬所有資源並終止線程執行。

終止不是即時的。 (無論如何,錯誤的線程正在運行。)

它在預定義的條件下發生 - 最方便的方法是調用boost::this_thread::sleep();,您可以定期使用該線程。

4

如果升級線程在I/O操作上阻塞(例如cin>>whatever),則boost::thread::terminate()不會終止該線程。 cin I/O不是有效的終止點。抓22.

1

我也有類似的問題我自己,並已達到該解決方案,這個問題的一些其他的讀者可能會發現有用:

假設你正在使用一個條件變量與等待()命令,它對於您來說知道在Boost中,wait()語句是一個自然中斷點非常重要。所以,只需在wait語句的代碼周圍放一個try/catch塊,並允許函數在catch塊中正常終止。

現在,假設你有一個帶有線程指針的容器,迭代你的線程指針並在每個線程上調用interrupt(),然後調用join()。

現在,所有線程都將優雅地終止,任何與Boost相關的內存清理都應該乾淨地工作。

0

很晚了,但在Windows中(它是像VMS或RSX這樣的前驅體,用於那些重播這樣的事情)我會用ReadFileEx這樣的完成例程來完成信號,而CancelIO如果讀取需要被取消早。

Linux/BSD有一個完全不同的底層API,它不那麼靈活。使用pthread_kill發送信號適用於我,這將停止讀取/打開操作。

這是值得在這個領域爲每個平臺,恕我直言,實施不同的代碼。