如果您有待处理的操作,例如

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,则故意导致故障,因此无需采取任何措施。

最佳答案

框架不直接支持此功能。最好的选择是编写一个包装器,该包装器产生一个线程并使用事件之类的同步原语来发出取消请求。

高温超导

非洲科尔比

关于c# - 如何终止待处理的APM操作,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/385381/

10-13 07:47