2009-08-22 5 views
1

В последнее время я делаю серийные коммуникации, поэтому я подготовил класс, являющийся простым интерфейсом ко всем функциям 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

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

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

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

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

+0

Спасибо за ваше предложение.Возможно, вы правы, но я все равно хотел бы узнать ответ на мои вопросы. Это мое любопытство или, скорее, желание расширить мои знания по этой теме. –