Como eliminar uma operação APM pendente

Se você tiver uma operação pendente, por exemplo,

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

e você fecha o provedor de stream, por exemplo

serialPort.Close();

você surpreendentemente causa uma exceção.

Existe um método preferido pelo qual se pode cancelar uma operação APM pendente antes de fechar a porta?

A resposta de Colby não é a resposta que eu esperava, mas ele fecha pelo menos uma avenida infrutífera no inquérito.

Felizmente encontrei uma solução.

Para cada fluxo, mantenho várias informações de estado em uma classeDeviceSession. Esta classe tem um métodoReadStream fornecendo a implementação para oAsyncCallback que lida com dados recebidos.

Observe que_asyncCallbackRead e todas as outras variáveis que começam com um sublinhado são um membro privado de classe atribuído no construtor de DeviceSession.

O construtor também fornece a chamada inicial para_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);
    }
}

Observe que não me preocupei em definirar.AsyncState. Como o delegado de retorno de chamada se refere ao método de uma instância específica do DeviceSession, informações detalhadas e fortemente tipadas do contexto (contidas nos membros dessa instância do DeviceSession) sãoautomaticamente na mira. Este é o ponto de ter um objeto de sessão.

De volta ao assunto de abortar um ouvinte, o fechamento do provedor de fluxo aciona o retorno de chamada, mas a tentativa de chamar os resultados do EndRead em umIOException.

Geralmente, essa exceção indica uma falha que requer a reinicialização do ouvinte e é recomendável responder reiniciando o provedor de fluxo e recriando a sessão. Isso é complicado pela ausência de uma maneira confiável e independente do provedor de fluxo para determinar se o provedor falhou ou o usuário está tentando reiniciar a conexão (por exemplo, conectou um novo dispositivo à porta).

O truque é adicionar mais contexto (IsOpen) aoDeviceSession para indicar se a sessão está aberta ou foi fechada e use-a para concluir sem problemas a execução final abortiva deReadStream.

E seIsOpen étrue então umIOException representa uma falha na necessidade de recuperação. E seIsOpen éfalse a falha foi induzida deliberadamente e nenhuma ação é necessária.

questionAnswers(2)

yourAnswerToTheQuestion