Последовательный порт и обработка ошибок при перекрывающихся операциях ввода-вывода - PullRequest
1 голос
/ 22 августа 2009

В последнее время я выполняю последовательную связь, поэтому я подготовил класс, представляющий собой простой интерфейс для всех тех функций Windows API, которые отвечают за чтение, запись и т. Д. Все операции ввода-вывода внутри этого класса обрабатываются асинхронно.

Прежде чем перейти к моему вопросу, позвольте мне показать вам, как я пишу и читаю данные с последовательного порта (это только функция чтения, потому что структура пишущей точно такая же, поэтому нет смысла представлять оба из них).

function TSerialPort.Read(var pBuffer; const lBufferSize: Cardinal): Cardinal;
var
  lOverlapped: OVERLAPPED;
  lLastError: Cardinal;
  lEvent: TEvent;
begin
  lEvent := TEvent.Create(nil, True, False, '');
  try
    FillChar(lOverlapped, SizeOf(lOverlapped), 0);
    lOverlapped.hEvent := lEvent.Handle;

    if not ReadFile(FSerialPortHandle, pBuffer, lBufferSize, Result, @lOverlapped) then
    begin
      lLastError := GetLastError;
      if (lLastError <> ERROR_IO_PENDING) and (lLastError <> ERROR_SUCCESS) then
        raise Exception.Create(SysErrorMessage(lLastError));

      case lEvent.WaitFor(INFINITE) of
        wrSignaled:
          if not GetOverlappedResult(FSerialPortHandle, lOverlapped, Result, False) then
            raise Exception.Create(SysErrorMessage(GetLastError));

        wrError:
          begin
            lLastError := lEvent.LastError;
            //this is a call to Windows.CancelIo(FSerialPortHandle);
            if Self.CancelIO() then
              lEvent.WaitFor(INFINITE);
            raise Exception.Create(SysErrorMessage(lLastError));
          end;
      end;
    end;
  finally
    FreeAndNil(lEvent);
  end;
end;

Прежде чем вы спросите меня, почему я открываю последовательный порт для перекрывающихся операций, пока эта функция ожидает завершения операции чтения, вот мое объяснение - только при открытии последовательного порта таким способом я могу указать время, в течение которого метод WaitCommEvent () ожидает события. Если бы я открыл порт для неперекрывающихся операций, WaitCommEvent () блокировался до тех пор, пока на последовательном порту не появилось событие, которое не могло бы всегда вызывать блокировку вызывающего потока навсегда.

Тем не менее, давайте сосредоточимся на вышеупомянутой функции Read ().

1) Прежде всего, я жду без каких-либо ограничений времени для установки события. Есть ли вероятность того, что текущий поток по какой-то причине заблокируется навсегда? Я не знаю, могу ли я быть на 100% уверенным, что событие рано или поздно будет установлено потоком, выполняющим операцию чтения асинхронно. Я знаю, что когда все таймауты чтения последовательного порта установлены на ноль, операция чтения не завершится, пока не будет прочитано заданное количество байтов, но это поведение, которое я знаю. Мой вопрос касается неожиданных ситуаций, которые могут привести к тому, что событие никогда не будет установлено, и метод WaitFor () будет ждать вечно - это может произойти?

2) WaitFor () может возвращать wrError, которая сообщает, что во время операции ожидания произошла какая-то ошибка (но это вообще не связано с перекрывающейся операцией чтения, верно?). Поэтому я думаю, что мне больше не нужно ждать завершения операции чтения, поскольку дескриптор события может больше не использоваться, верно? Поэтому я вызываю метод CancelIO (), чтобы отменить операцию чтения, подождать, пока поток не установит поток, асинхронно выполняющий отмененное чтение, и только затем вызвать исключение. Я жду, чтобы чтение было отменено этим потоком, потому что, если бы я немедленно покинул свой метод Read () (без отмены ввода-вывода), я бы заставил этот поток записать свои данные (перекрывающиеся данные записи) в локальные переменные, которые быть больше не действительным, верно? С другой стороны, существует ли опасность того, что текущий поток будет заблокирован навсегда из-за вызова WaitFor (INFINITE) перед вызовом исключения?

Буду признателен, если вы сообщите мне, верны ли приведенные выше утверждения или нет, и прокомментируйте их, пожалуйста.

Большое спасибо заранее.

1 Ответ

1 голос
/ 22 августа 2009

Просто из любопытства: почему вы не используете существующий последовательный компонент?

Я использую TurboPower Async для получения сообщений GPS, но есть множество других свободно доступных: http://www.efg2.com/Lab/Library/Delphi/IO/PortIO.htm

Большинство из них позволяют вам осуществлять последовательную связь на гораздо более высоком уровне, абстрагируя от вас все низкоуровневые операции ввода-вывода и нити.

Таким образом, вам нужно только написать обработчик onreceive для получения и вызвать send() для отправки материала.

...