1

我最近一直在做串行通信,所以我准备了一个类,它是所有负责读取、写入等的 Windows API 函数的简单接口。这个类中的所有 I/O 操作都是异步处理的。

在我开始我的问题之前,让我告诉你我是如何从串口写入和读取数据的(这只是读取功能,因为写入的结构完全相同,所以没有必要同时呈现它们) .

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() 方法(不取消 I/O),我会导致该线程将其数据(重叠的记录数据)写入本地变量,这将那么就不再有效了,对吧?另一方面,

如果您告诉我上述陈述是否属实,我将不胜感激,并请发表评论。

非常感谢您提前。

4

1 回答 1

1

只是出于好奇:为什么不使用现有的串行组件?

我使用TurboPower Async来接收 GPS 消息,但还有很多其他免费可用的:http ://www.efg2.com/Lab/Library/Delphi/IO/PortIO.htm

其中大多数允许您在更高级别进行串行通信,为您抽象出所有较低级别的 IO 和线程内容。

这样你只需要编写一个onreceive处理程序来接收,并调用send()发送东西。

于 2009-08-22T15:42:35.677 回答