问题描述
如果您有待处理的操作,例如
If you have a pending operation, eg
stream.BeginRead(_buffer, 0, _buffer.Length, _asyncCallbackRead, this);
,然后关闭流提供程序,例如
and you close the stream provider, eg
serialPort.Close();
毫无疑问,您会引发异常。
you unsurprisingly cause an exception.
在关闭端口之前,有没有一种首选的方法可以用来取消挂起的APM操作?
Is there an preferred method by which one might cancel a pending APM operation, prior to closing the port?
Colby的答复是不是我希望的答案,但他至少确实关闭了一条毫无结果的查询渠道。
Colby's reply is not the answer I hoped for, but he does at least close off a fruitless avenue in inquiry.
我很高兴找到了解决方案。
Happily I have found a solution.
对于每个流,我在 DeviceSession
类中维护各种状态信息。此类具有方法 ReadStream
,该方法提供用于处理传入数据的 AsyncCallback
的实现。
For each stream I maintain various state information in a class DeviceSession
. This class has a method ReadStream
providing the implementation for the AsyncCallback
that handles incoming data.
请注意, _asyncCallbackRead
和其他所有以下划线开头的变量是在DeviceSession构造函数中分配的类私有成员。
Note that _asyncCallbackRead
and every other variable beginning with an underscore is a class private member assigned in the constructor of DeviceSession.
构造函数还提供对 _stream.BeginRead
的初始调用。
The constructor also provides the initial call to _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的此实例的成员中)在范围内自动 。这就是拥有会话对象的重点。
Notice that I haven't bothered to set ar.AsyncState
. Because the callback delegate refers to the method of a specific instance of DeviceSession, detailed and strongly typed context information (contained in the members of this instance of DeviceSession) is automatically in scope. This is the point of having a session object.
返回中止监听器的主题,关闭流提供程序会触发回调,但是尝试在 IOException
。
Back on the subject of aborting a listener, closing the stream provider triggers the callback but attempting to invoke EndRead results in an IOException
.
通常,此类异常表示需要重新启动侦听器的故障,并且人们希望通过重新启动流提供程序并重新创建会话来做出响应。由于缺乏可靠的,独立于流提供者的方式来确定提供者是否出故障还是用户正在尝试重新建立连接(例如,将新设备插入端口),这使情况变得复杂。
Generally such an exception indicates a fault requiring a listener restart and one will want to respond by restarting the stream provider and recreating the session. This is complicated by the absence of a reliable stream-provider-independent way to determine whether the provider has faulted or the user is trying to restart the connection (eg plugged a new device into the port).
诀窍是向 DeviceSession
添加更多上下文( IsOpen
)。会话已打开或已关闭,并使用它顺利完成 ReadStream
的最终中止执行。
The trick is to add more context (IsOpen
) to the DeviceSession
to indicate whether the session is open or has been closed, and use it to smoothly complete the final abortive execution of ReadStream
.
如果 IsOpen
为 true
,则 IOException
表示需要失败恢复。如果 IsOpen
为 false
,则故意导致失败,因此无需采取任何措施。
If IsOpen
is true
then an IOException
represents a failure in need of recovery. If IsOpen
is false
the failure was deliberately induced and no action is required.
推荐答案
框架中不直接支持此功能。最好的选择是编写一个包装器,该包装器产生一个线程并使用事件之类的同步原语来发出取消请求。
This is not directly supported in the framework. Your best bet is to write a wrapper that spawns a thread and use synchronization primitives like events to signal a cancel request.
HTH
Colby Africa
Colby Africa
这篇关于如何终止待处理的APM操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!