В последнее время я выполняю последовательную связь, поэтому я подготовил класс, представляющий собой простой интерфейс для всех тех функций 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) перед вызовом исключения?
Буду признателен, если вы сообщите мне, верны ли приведенные выше утверждения или нет, и прокомментируйте их, пожалуйста.
Большое спасибо заранее.