2011-08-27 24 views
3

的read()操作取消線程,我用連接到串口的設備進行通信。現在,我正在等待串行設備發送某些字節的特定消息。對於讀取操作(以及收到所需消息後的反應),我創建了一個新線程。根據用戶請求,我希望能夠取消該線程。在我的Cocoa項目中用串口

正如蘋果在docs中建議的那樣,我在線程字典中添加了一個標誌,定期檢查標誌是否已設置,如果是,請致電[NSThread exit]。這工作正常。現在

,線可能會被卡住等待串行設備到最後發送12字節的消息。讀取調用看起來是這樣的:

numBytes = read(fileDescriptor, buffer, 12); 

一旦線程開始讀設備,但沒有數據進來,我可以設置標誌告訴線程結束,但線程不會閱讀標誌,除非它最終收到至少12個字節的數據並繼續處理。

有沒有辦法殺死當前在串口設備上執行讀操作的線程?

編輯澄清: 我不創造與串行設備的I/O操作一個單獨的線程堅持。如果有一種方法可以封裝操作,以便我可以在用戶按下取消按鈕時「殺死」它們,我非常高興。 我正在爲桌面Mac OS X開發Cocoa應用程序,因此不會對移動設備及其功能施加任何限制。 解決方法是,如果沒有要讀取的字節,則立即返回讀取函數。我怎樣才能做到這一點?

回答

2

使用selectpoll與超時檢測時描述符準備好讀。

將超時設置爲(比如說)半秒,並調用它在一個循環,同時檢查,看看你的線程應該退出。

異步線程取消幾乎總是一個壞主意。嘗試堅持使用事件驅動的接口(並在必要時超時)。

+1

這是一個非常糟糕的做法。你永遠不應該編寫經常喚醒並輪詢變量的應用程序。這破壞了電池的使用壽命,聽起來像OP正在爲移動設備編寫這個文件,這是一個大問題......您可以通過在您的'select' /'poll'中添加一個管道來消除超時/喚醒,調用,並通過管道發送中止請求。 –

+0

我正在開發桌面Mac OS X,因此沒有移動設備的限制。 –

1

這也正是pthread_cancel接口是專爲。你會想包裝在pthread_cleanup_pushreadpthread_cleanup_pop的塊,在這個線程,你不想運行命令,你可以安全地清理如果線程被取消,並且還禁止取消(與pthread_setcancelstate)在其他代碼可以取消。如果適當的清理會涉及多個呼叫幀,這可能是一個痛苦;它基本上迫使您在每個調用級別使用pthread_cleanup_push,並使用try/catch樣式異常處理來構造線程代碼,如C++或Java。

一種替代方法將是沒有SA_RESTART標誌安裝一個信號處理程序的另外未使用的信號(如SIGUSR1或實時信號中的一個),這樣,它中斷系統調用與EINTR。信號處理器本身可以是一個完整的無操作;它唯一的目的是打斷事情。然後,您可以使用pthread_kill來中斷特定線程中的read(或任何其他系統調用)。這樣做的好處是您不必將代碼切換爲使用C++/Java類型的習慣用法。您可以通過檢查一個標誌(指示線程是否被請求中止)來處理EINTR錯誤,並且如果該標誌未設置,則恢復讀取,或者返回導致調用者清除並最終返回的錯誤代碼,並最終返回pthread_exit

如果確實使用中斷信號處理程序,請確保可返回EINTR的所有系統調用都包含在循環中,以便在EINTR上重試(或檢查中止標誌並可選擇重試)。否則,事情可能會嚴重破壞。

+0

這是一個非常非常糟糕的方法。使用一個信號和'EINTR'會產生一個不可避免的競爭條件,因爲信號可能在線程進入read()之前傳遞。因此,讀取不會被中斷,並且會永久阻止,但只有當競爭條件觸發時...使錯誤極難複製和修復。輪詢幾乎是無限優選的。 (也就是說,我同意最好的答案是在選擇/投票中添加一個管道。) – Nemo

+0

在OP所要求的交互式使用中,「永遠的塊」將真正「阻塞,直到用戶再次按下取消按鈕」 。我同意這裏有一個競賽條件,這可能不是一件容易的事情。對於一般情況,我可以想象一個複雜的框架,其中包含一個不重要的信號處理程序,並且longjmps可以滿足要求,但不會產生任何異步信號安全違規或其他UB,但這可能不是OP所要求的。 。 –

相關問題