2008-12-22 23 views
2

如果你有一個掛起操作,如如何殺死一個掛起APM操作

stream.BeginRead(_buffer, 0, _buffer.Length, _asyncCallbackRead, this); 

,並關閉該流供應商,如

serialPort.Close(); 

你意料之中導致異常。

在關閉端口之前,有人可能會取消未決的APM操作嗎?


科爾比的回答並不是我所希望的答案,但他至少確實關閉了一個沒有結果的調查渠道。

很高興我找到了解決方案。

對於每個流,我維護一個類DeviceSession中的各種狀態信息。該類有一個方法ReadStream,提供處理傳入數據的AsyncCallback的實現。

請注意,_asyncCallbackRead和以下劃線開頭的每個其他變量都是在DeviceSession的構造函數中分配的類私有成員。

構造函數還提供了對_stream.BeginRead的初始調用。

void ReadStream(IAsyncResult ar) 
{ 
    if (IsOpen) 
    try 
    { 
     DevicePacket packet; 
     int cbRead = _stream.EndRead(ar); 
     _endOfValidData += cbRead; 
     while ((packet = GetPacket()) != null) 
     CommandStrategy.Process(this, packet); 
     _stream.BeginRead(_buffer, _endOfValidData, 
     _buffer.Length - _endOfValidData, 
     _asyncCallbackRead, null); 
    } 
    catch (Exception ex) 
    { 
     Trace.TraceError("{0}\r\n{1}", ex.Message, ex.StackTrace); 
     _restart(_streamProvider, _deviceId); 
    } 
} 

請注意,我並沒有打算設置ar.AsyncState。因爲回調委託引用了DeviceSession的特定實例的方法,所以在範圍內,詳細和強類型的上下文信息(包含在此實例的DeviceSession的成員中)自動爲。這是擁有會話對象的要點。

返回關於中止偵聽器的主題,關閉流提供程序會觸發回調,但會嘗試調用IOException中的EndRead結果。

通常,這樣的異常指示需要偵聽器重新啓動的故障,並且會想要通過重新啓動流提供程序並重新創建會話來作出響應。由於缺乏可靠的與流提供商無關的方式來確定提供商是否出現故障或用戶正在嘗試重新啓動連接(例如,將新設備插入端口),這很複雜。

關鍵是要更多的內容(IsOpen)添加到DeviceSession指示所述會話是打開還是已關閉,並用它來順利的完成的ReadStream最終流產執行。

如果IsOpentrue那麼IOException代表需要恢復的故障。如果IsOpenfalse故障是故意引起的,不需要採取任何措施。

回答

0

這不是直接支持框架。你最好的選擇是寫一個產生線程的包裝器,並使用像事件這樣的同步原語來表示取消請求。

HTH

科爾比非洲

2

[由Richter的CLR通過C#在APM的一章,我決定看看有什麼好東西所以不得不關於這個問題,我發現這個問題的啓發。我認爲Peter在這裏有一個很好的問題,並做了一些研究 - 這是結果]

Jeffrey Richter在CLR中通過C#(第27章)討論了他的AsyncEnumerator類(據推測)會帶走很多痛苦從編程APM。這個類別的特徵之一(他免費提供的Power Threading Libary的一部分)是取消異步操作的能力。

該類可以從上面的鏈接下載。該頁面還包含一個指向Yahoo Group Richter的鏈接,該鏈接爲lib提供了有限的支持。

他介紹,這些MSDN文章庫:

Simplified APM With The AsyncEnumerator
More AsyncEnumerator Features