保留中の操作がある場合、たとえば
stream.BeginRead(_buffer, 0, _buffer.Length, _asyncCallbackRead, this);
ストリームプロバイダーを閉じます。
serialPort.Close();
当然のことながら、例外が発生します。
ポートを閉じる前に、保留中の APM 操作をキャンセルするための推奨される方法はありますか?
Colby の返答は、私が望んでいたものではありませんが、少なくとも無駄な調査の道を閉ざしてくれます。
幸いなことに、私は解決策を見つけました。
ストリームごとに、さまざまな状態情報を class に保持し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 のこのインスタンスのメンバーに含まれる) は自動的にスコープに含まれます。これが、セッション オブジェクトを持つポイントです。
リスナーの中止に戻ると、ストリーム プロバイダーを閉じるとコールバックがトリガーされますが、EndRead を呼び出そうとするとIOException
.
通常、このような例外は、リスナーの再起動が必要な障害を示しており、ストリーム プロバイダーを再起動してセッションを再作成することで対応する必要があります。これは、プロバイダーに障害が発生したか、ユーザーが接続を再開しようとしているか (たとえば、新しいデバイスをポートに接続したか) を判断する信頼できるストリーム プロバイダーに依存しない方法がないため、複雑です。
IsOpen
秘訣は、さらにコンテキスト ( ) をに追加しDeviceSession
て、セッションが開いているか閉じているかを示し、それを使用して の最終的な中止実行をスムーズに完了することですReadStream
。
の場合IsOpen
はtrue
、IOException
回復が必要な障害を表します。IsOpen
障害がfalse
意図的に引き起こされたものであり、アクションは不要な場合。