Как убить ожидающую операцию 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)автоматически в рамках. Это точка наличия объекта сеанса.
Возвращаясь к теме прерывания слушателя, закрытие потокового провайдера вызывает обратный вызов, но попытка вызвать EndRead приводит кIOException
.
Как правило, такое исключение указывает на ошибку, требующую перезапуска слушателя, и можно захотеть ответить путем перезапуска поставщика потока и повторного создания сеанса. Это осложняется отсутствием надежного независимого от поставщика потокового способа определения того, провайдер отказал или пользователь пытается перезапустить соединение (например, подключил новое устройство к порту).
Хитрость заключается в том, чтобы добавить больше контекста (IsOpen
) кDeviceSession
чтобы указать, открыт ли сеанс или был закрыт, и использовать его для плавного завершения окончательного неудачного выполненияReadStream
.
ЕслиIsOpen
являетсяtrue
затемIOException
представляет собой сбой, нуждающийся в восстановлении. ЕслиIsOpen
являетсяfalse
отказ был умышленно вызван, и никаких действий не требуется.