在C语言中获取Windows串口输入缓冲区长度

4

在Windows下使用C语言,是否有一种非阻塞函数可以返回串口的当前rx队列长度?

我看到的所有示例都只是调用ReadFile函数,该函数会一直阻塞直到超时,所以我想知道在读取之前是否有可能检查缓冲区中是否有数据?

例如,针对每个字符,我可以简单地执行以下操作:

void ReadCharacter(char *theCharacter)
{
   DWORD numBytesRead = 0;

   while (numBytesRead == 0)
   {
        ReadFile(comPorthandle,
               theCharacter,
               sizeof(char),
               &numBytesRead,
               NULL);
   }
}

但是,是否可能有像这样的东西呢?
int numBytesRx = GetNumBytesRx(&portHandle);
if (numBytesRx > 0)
    Read(&portHandle, targetBuffer, numBytesRead);

你可以使用超时 - LPs
2个回答

4

如果要通过ReadFile执行与COM端口的异步IO,请考虑使用函数的最后一个参数LPOVERLAPPEDOVERLAPPED结构。在Windows中,OVERLAPPED是异步IO的常见做法。

在这里您可以找到示例


1
如果你需要回调函数,可以使用 ReadFileEx。 - Lundin
@Lundin 这只是另一种做事情的方式。我不会说它更容易,因为当你想要接收回调时,你需要让你的线程处于可警告状态并且你需要一个单独的过程。 - V. Kravchenko
在进行任何形式的I/O时,您应该始终拥有单独的线程。是的,这往往会变得有点复杂。 - Lundin

2
ReadFile将始终返回rx缓冲区中的内容。因此,如果您没有设置超时,您会立即获得内容。
请注意,没有专业应用程序会将ReadFile放在繁忙的等待循环中。这不仅会不必要地使用CPU,还会阻塞存在循环的线程。
因此,您应该将ReadFile放在自己的线程中。这是所有I/O函数的常见做法。这将解决阻塞问题,但您仍然会遇到高CPU使用率的问题。
作为替代方案,您可以使用Windows所谓的"异步I/O"(*),通过使用ReadFileEx函数。它允许您指定一个回调函数,每当您实际接收到一些数据时,它就会触发。
现在,如果您将"异步I/O"与线程组合使用,您将获得一种非阻塞通信方式,在没有要处理的数据时不会消耗任何CPU。您的I/O线程可以使用SleepEx等待I/O,或者它可以使用WaitFor等待您在回调内部手动设置的事件。
(*) "异步I/O"是无意义的Windows术语,因为从技术上讲,所有串行端口通信都始终是异步的。如果您同步发送没有间隔的数据,慢速台式电脑将无法跟上。

异步 I/O 从程序员的角度是异步的,即程序员提供的缓冲区传输数据是异步发生的。与硬件正在执行什么无关! - Harry Johnston
@HarryJohnston 当然它与硬件有关,因为字节按照硬件规定出现在缓冲区中。同步/异步通信是明确定义的技术术语。不要陷入听取微软试图将全球每一个行业事实上标准术语重新命名为其他名称的陷阱中。 - Lundin
@Lundin:嗯,我不确定他们是否应该用不同的名称命名它,但是我认为从API的角度来看这并不含糊。事实上,ReadFile阻塞了本质上异步的操作,而ReadFileEx则没有。当进行低级编程时,这一点绝对需要知道。但是,如果ReadFileEx只是在幕后生成一个后台线程并读取一个阻塞方法,那么它对我的代码会产生什么影响,我并不明白。 - Lou
@LousyCoder ReadFileEx不会生成线程,它只是在有数据可读时执行回调函数。我只是建议您将所有I/O操作放在单独的线程中,这样可以为您提供良好的程序设计。 - Lundin
不仅微软使用这个词的方式,还有,在这里看到第二定义,以及Linux信号的页面,其中包括"异步地通过信号处理器捕获信号"的短语。有时候一个词确实可以合法地有多个意思。(我同意"异步通讯"这个短语有一个约定俗成的含义,但是问题的短语是"异步I/O"。在API上下文中,不是同一回事。) - Harry Johnston
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接