C++ 如何使用 COMMTIMEOUTS 等待字节可用但读取多个字节?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10390151/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:00:23  来源:igfitidea点击:

How do I use COMMTIMEOUTS to wait until bytes are available but read more than one byte?

c++winapiserial-portcommunication

提问by sprite

I have a C++ serial port class that has a none blocking and a blocking mode for read operations. For blocking mode:

我有一个 C++ 串行端口类,它具有无阻塞和用于读取操作的阻塞模式。对于阻塞模式:

COMMTIMEOUTS cto;
GetCommTimeouts(m_hFile,&cto);
// Set the new timeouts
cto.ReadIntervalTimeout = 0;
cto.ReadTotalTimeoutConstant = 0;
cto.ReadTotalTimeoutMultiplier = 0;
SetCommTimeouts(m_hFile,&cto)

For non blocking mode:

对于非阻塞模式:

COMMTIMEOUTS cto;
GetCommTimeouts(m_hFile,&cto);
// Set the new timeouts
cto.ReadIntervalTimeout = MAXDWORD;
cto.ReadTotalTimeoutConstant = 0;
cto.ReadTotalTimeoutMultiplier = 0;
SetCommTimeouts(m_hFile,&cto)

I would like to add another mode that waits for any number of bytes and read them.

我想添加另一种等待任意数量字节并读取它们的模式。

From MSDN COMMTIMEOUTS structure:

从 MSDN COMMTIMEOUTS 结构

If an application sets ReadIntervalTimeoutand ReadTotalTimeoutMultiplierto MAXDWORDand sets ReadTotalTimeoutConstantto a value greater than zero and less than MAXDWORD, one of the following occurs when the ReadFile function is called:

如果应用程序将ReadIntervalTimeoutReadTotalTimeoutMultiplier 设置MAXDWORD并将ReadTotalTimeoutConstant设置为大于零且小于MAXDWORD 的值,则在调用 ReadFile 函数时会发生以下情况之一:

  • If there are any bytes in the input buffer, ReadFile returns immediately with the bytes in the buffer.
  • If there are no bytes in the input buffer, ReadFile waits until a byte arrives and then returns immediately.
  • If no bytes arrive within the time specified by ReadTotalTimeoutConstant, ReadFile times out.
  • 如果输入缓冲区中有任何字节,ReadFile 会立即返回缓冲区中的字节。
  • 如果输入缓冲区中没有字节,ReadFile 会等待一个字节到达,然后立即返回。
  • 如果在 ReadTotalTimeoutConstant 指定的时间内没有字节到达,则 ReadFile 超时。

This looks in code like this:

这看起来像这样的代码:

COMMTIMEOUTS cto;
GetCommTimeouts(m_hFile,&cto);
// Set the new timeouts
cto.ReadIntervalTimeout = 100;
cto.ReadTotalTimeoutConstant = MAXDWORD;
cto.ReadTotalTimeoutMultiplier = MAXDWORD;
SetCommTimeouts(m_hFile,&cto)

But this returns emidiately on the first byte. This is a problem since I am reading the port in a loop and the handling of a byte is so fast that the next time I read the port, only another byte is available. The end result is that I am reading one byte at a time in a loop and using 100% of the core running that thread.

但这会在第一个字节上立即返回。这是一个问题,因为我正在循环读取端口,并且字节的处理速度非常快,以至于下次我读取端口时,只有另一个字节可用。最终结果是我在循环中一次读取一个字节,并使用 100% 的内核运行该线程。

I would like to use the cto.ReadIntervalTimeoutlike in the MSDN documentation but still wait until at least one byte is available. Does anyone have an idea?

我想cto.ReadIntervalTimeout在 MSDN 文档中使用类似的东西,但仍然要等到至少有一个字节可用。有没有人有想法?

Thanks.

谢谢。

回答by Ben Voigt

The behavior you want will come from:

你想要的行为将来自:

cto.ReadIntervalTimeout = 10;
cto.ReadTotalTimeoutConstant = 0;
cto.ReadTotalTimeoutMultiplier = 0;

It blocks arbitrarily long for the first byte (total timeout is disabled by setting the latter two fields to zero, per the documentation), then reads up to the buffer size as long as data is streaming in. If there's a 10ms gap in the data, it will return with what has been received so far.

它为第一个字节阻塞任意长(根据文档,通过将后两个字段设置为零来禁用总超时),然后只要数据流入就读取缓冲区大小。如果数据中有 10 毫秒的间隙,它将返回到目前为止已收到的内容。

回答by Jerry Coffin

If you're using 100% (or even close to it) of the CPU, it sounds like you're doing something wrong elsewhere. As I showed in a previous answer, for years I've used code with the timeouts all set to 1. I initially set it that way just as a wild guess at something that might at least sort of work, with the intent of tuning it later. It's worked well enough that I've never gotten around to tuning it at all. Just for example, it'll read input from my GPS (about the only thing I have that even imitates using a serial port any more) using an almost immeasurably tiny amount of CPU time -- after hours of reading a constant stream of data from the GPS, it still shows 0:00:00 seconds of CPU time used (and I can't see any difference in CPU usage whether it's running or not).

如果您正在使用 100%(甚至接近)的 CPU,那么听起来您在其他地方做错了。正如我在之前的回答中所展示的,多年来我一直使用超时设置为 1 的代码。我最初将它设置为这种方式,只是对可能至少有某种工作的东西进行了疯狂的猜测,目的是对其进行调整之后。它运行良好,以至于我根本没有时间调整它。举个例子,它会使用几乎无法估量的 CPU 时间从我的 GPS 中读取输入(大约是我唯一可以模仿使用串行端口的东西)——在读取了几个小时的恒定数据流之后GPS,它仍然显示 0:00:00 秒的 CPU 使用时间(无论是否运行,我都看不到 CPU 使用率的任何差异)。

Now, I'll certainly grant that a GPS isn't (even close to) the fastest serial device around, but we're still talking about ~100% vs. ~0%. That's clearly a pretty serious difference.

现在,我肯定承认 GPS 不是(甚至接近于)最快的串行设备,但我们仍在谈论 ~100% 与 ~0%。这显然是一个非常严重的差异。

回答by HERU

if (dwEvtMask == EV_RXCHAR )
{
   Sleep(1);
   if (dwLength > 2)
    {
      Sleep(1);
      Readfile( m_Serial->m_hCom, data,dwLength, &dwBytesRead, &Overlapped);
      pDlg->PostMessage(WM_RECEIVE,0,0);
    }
}