Linux 无需高 CPU 使用即可读取串行数据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7035526/
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
Read serial data without high CPU use
提问by darkadept
I want to read messages sent from an Arduino via the FTDI (serial) interface in a simple C or C++ program under Linux. The Arduino sends a two character 'header', a command byte followed by a few bytes of data depending on the command.
我想在 Linux 下通过简单的 C 或 C++ 程序中的 FTDI(串行)接口读取从 Arduino 发送的消息。Arduino 发送一个两个字符的“标题”,一个命令字节,后跟几个字节的数据,具体取决于命令。
My first attempt was to simply poll the data using open() and read() but doing so causes about 12% CPU use. This didn't seem to be the appropriate way of doing things.
我的第一次尝试是简单地使用 open() 和 read() 轮询数据,但这样做会导致大约 12% 的 CPU 使用率。这似乎不是正确的做事方式。
Second I read up on libevent on implemented an event loop that fires an event when data is present on the file descriptor. My cpu usage was next to nothing but I couldn't read the entire message before another event was called. The events didn't fire when an entire message was received but as soon as any/some data was available on the file descriptor. Looking at it more it was obvious that this wouldn't work quite the way I wanted it. This is my event code: http://pastebin.com/b9W0jHjb
其次,我在 libevent 上阅读了实现的事件循环,该循环在文件描述符上存在数据时触发事件。我的 CPU 使用率几乎为零,但在调用另一个事件之前我无法阅读整个消息。当接收到整个消息时,事件不会触发,但只要文件描述符上有任何/某些数据可用,就会触发事件。再仔细看看,很明显这不会像我想要的那样工作。这是我的事件代码:http: //pastebin.com/b9W0jHjb
Third I implemented a buffered event with libevent. It seemed to work somewhat better but still split some of the messages up. My event code is: http://pastebin.com/PQNriUCN
第三,我用 libevent 实现了一个缓冲事件。它似乎工作得更好,但仍将一些消息分开。我的事件代码是:http: //pastebin.com/PQNriUCN
Fourth I dumped libevent and tried out Boost's ASIO class. The example I was following was http://www.webalice.it/fede.tft/serial_port/serial_port.html. It seemed to work alright but the "event loop" was a "while(1) {}" which caused CPU usage to go up again. The loop just checks for error status while serial reading happens in a callback on a different thread. I added a usleep(1) to the while loop and it brought my CPU usage to 2% which is ok, but still seems heavy for such a light program.
第四,我放弃了 libevent 并尝试了 Boost 的 ASIO 类。我遵循的示例是http://www.webalice.it/fede.tft/serial_port/serial_port.html。它似乎工作正常,但“事件循环”是“while(1) {}”,导致 CPU 使用率再次上升。循环只是检查错误状态,而串行读取发生在不同线程的回调中。我在 while 循环中添加了一个 usleep(1),它使我的 CPU 使用率达到了 2%,这是可以的,但对于这样一个轻量级的程序来说似乎仍然很重。
Most of the examples of libevent and even the underlying epoll use TCP sockets which doesn't seem to behave quite the same as serial port data.
libevent 的大多数示例甚至底层的 epoll 都使用 TCP 套接字,这似乎与串行端口数据的行为不太一样。
So my main question is: what is a good lightweight way to read messages from a serial port without heavy polling? (in linux, using C or C++)
所以我的主要问题是:在没有大量轮询的情况下从串行端口读取消息的轻量级方法是什么?(在 linux 中,使用 C 或 C++)
采纳答案by Simon Elliott
The OP has probably long since solved this, but for the sake of anyone who gets here by google:
OP 可能早就解决了这个问题,但为了任何通过谷歌到达这里的人:
#include <sys/poll.h>
struct pollfd fds[1];
fds[0].fd = serial_fd;
fds[0].events = POLLIN ;
int pollrc = poll( fds, 1, 1000);
if (pollrc < 0)
{
perror("poll");
}
else if( pollrc > 0)
{
if( fds[0].revents & POLLIN )
{
char buff[1024];
ssize_t rc = read(serial_fd, buff, sizeof(buff) );
if (rc > 0)
{
/* You've got rc characters. do something with buff */
}
}
}
Make sure the serial port is opened in nonblocking mode as poll() can sometimes return when there are no characters waiting.
确保串行端口以非阻塞模式打开,因为 poll() 有时会在没有字符等待时返回。