简体   繁体   English

异步串行通信:为什么ReadFile()在OVERLAPPED结构中设置事件?

[英]Assynchronous serial comms: why does ReadFile() set the event in the OVERLAPPED struct?

I have drawn on various sources to piece together some (multi-threaded) code to read and write from/to a serial port. 我已经利用各种资源将一些(多线程)代码拼凑在一起,以便从串行端口读写数据。 It all works fine... except that the loop in the thread that does the reading from the serial port unintentionally does a busy wait. 一切正常……除了在线程中无意中从串行端口读取数据的循环进行了繁忙的等待。 Essentially what happens repeatedly is: 本质上反复发生的是:

  • An event (created outside the read loop) is reset, and its handle used as the hEvent member in an OVERLAPPED struct. 重置事件(在读取循环外部创建),并将其句柄用作OVERLAPPED结构中的hEvent成员。
  • ReadFile() is passed the OVERLAPPED struct (among other parameters) and returns immediately ReadFile()被传递给OVERLAPPED结构(以及其他参数)并立即返回
  • WaitForSingleObject() waits on the event in the OVERLAPPED struct, but always returns immediately because the event is always set after the ReadFile() WaitForSingleObject()等待OVERLAPPED结构中的事件,但总是立即返回,因为该事件总是在ReadFile()之后设置
  • GetOverlappedResult() is then passed the same OVERLAPPED struct, returns successfully, but typically only reads 0 bytes 然后将GetOverlappedResult()传递给相同的OVERLAPPED结构,成功返回,但通常只读取0个字节

My expectation was that the whole point of the event was to signal when there is data available to read. 我的期望是该事件的全部目的是在有可用数据读取时发出信号。 But ReadFile() sets the event, and so what is the point? 但是ReadFile()设置了事件,那又有什么意义呢? What am I missing? 我想念什么?

The following stripped-back code demonstrates the issue on my system (I have COM3 connected). 下面的简化代码演示了我系统上的问题(我已连接COM3)。 The full code quite happily reads and writes... but the reader suffers from the condition described above: 完整的代码非常愉快地读取和写入...但是读者遭受上述情况的困扰:

HANDLE portHandle = CreateFile( "COM3",
                                GENERIC_READ | GENERIC_WRITE,
                                0,
                                NULL,
                                OPEN_EXISTING,
                                FILE_FLAG_OVERLAPPED,
                                NULL );  // succeeds
HANDLE readerEvent = CreateEvent( 0, TRUE, FALSE, _T( "Rx Event" ) );  // succeeds
char buffer[ 200 ];
DWORD bytesRead;
OVERLAPPED reader;
memset( &reader, 0, sizeof( reader ) );
reader.hEvent = readerEvent;
ResetEvent( readerEvent );
ReadFile( portHandle, buffer, 200, &bytesRead, &reader );
if ( WaitForSingleObject( reader.hEvent, 2000 ) == WAIT_OBJECT_0 )
{
    // always true, never has to wait on the event.
}

Found it: the documentation for the ReadFile function contains this paragraph: 找到了:ReadFile函数的文档包含以下段落:

  • When reading from a communications device, the behavior of ReadFile is determined by the current communication time-out as set and retrieved by using the SetCommTimeouts and GetCommTimeouts functions. 从通信设备读取时,ReadFile的行为由设置和使用SetCommTimeouts和GetCommTimeouts函数检索的当前通信超时确定。 Unpredictable results can occur if you fail to set the time-out values. 如果您无法设置超时值,则可能会发生不可预测的结果。 For more information about communication time-outs, see COMMTIMEOUTS. 有关通信超时的更多信息,请参见COMMTIMEOUTS。

I was not using SetCommTimeouts() at all. 我根本没有使用SetCommTimeouts()。 Performing a GetCommTimeouts() and inspecting the results showed the port's settings were the values described in this paragraph from the COMMTIMEOUTS documentation: 执行GetCommTimeouts()并检查结果表明端口的设置是COMMTIMEOUTS文档中本段中描述的值:

  • A value of MAXDWORD, combined with zero values for both the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies that the read operation is to return immediately with the bytes that have already been received, even if no bytes have been received. MAXDWORD的值与ReadTotalTimeoutConstant和ReadTotalTimeoutMultiplier成员的零值结合在一起,指定读取操作将立即返回已接收的字节,即使未接收到字节也是如此。

You can also use the WaitCommEvent function to wait on the event with a specific event mask. 您还可以使用WaitCommEvent函数等待具有特定事件掩码的事件。 Code sample using CreateFile and WaitCommEvent: Monitoring Communications Events . 使用CreateFile和WaitCommEvent的代码示例: 监视通信事件

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM