Boost串口引发嵌入式CPU单核心100%占用问题(关联Ticket#10496)
解决Boost串口等待数据导致CPU核心100%占用的问题
你碰到的这个问题确实和你提到的那个Boost官方ticket完全匹配,我之前在类似的Linux嵌入式平台上也遇到过——就是Boost.Asio的旧版本串口实现存在忙轮询(busy-wait)的bug,在Ubuntu 16.04这类环境下,当你只打开串口等待数据时,底层会不断循环检查串口状态,直接把单个CPU核心占满100%。
问题根源
在早期的Boost.Asio版本中,串口读操作的底层实现没有正确利用Linux的select/epoll等异步事件通知机制,反而采用了用户态的循环轮询方式。当串口没有数据时,这个循环不会阻塞,而是一直空转,直接耗尽单个核心的CPU资源。你的场景刚好是“仅打开串口等待数据”,完全触发了这个bug。
可行的解决方案
针对你的情况,推荐按优先级尝试以下方案:
优先升级Boost版本:这个bug已经在后续的Boost版本中被修复(大概是Boost 1.60及以后的版本)。如果你的项目依赖允许,直接升级到修复后的Boost版本,就能彻底解决问题,这也是最省心的办法。
手动优化串口等待逻辑(无法升级Boost时):
如果你暂时没办法升级Boost,可以通过调整串口参数或者修改读操作的实现方式,避免忙轮询:- 配置串口的
VMIN和VTIME参数:
利用Linux原生的串口终端属性,让底层驱动在没有数据时进入阻塞状态,而不是用户态轮询。结合你的代码结构,可以这样调整:// 先获取当前串口的终端属性 struct termios t; tcgetattr(serial_port->native_handle(), &t); // VMIN=1:至少等待1个字符才返回 // VTIME=0:无限等待,直到有数据到来 t.c_cc[VMIN] = 1; t.c_cc[VTIME] = 0; // 应用配置 tcsetattr(serial_port->native_handle(), TCSANOW, &t); // 之后再执行读操作,此时底层会阻塞直到有数据,不会空转 ba::read(*serial_port, ba::buffer(data_buffer)); - 改用异步读操作:
切换到Boost.Asio的异步读模式,配合io_service的正确运行方式,确保没有事件时io_service会阻塞,而不是空转。示例代码如下:// 创建work对象,防止io_service没有任务时退出 work_ptr work = std::make_shared<ba::io_service::work>(your_io_service); // 用单独的线程运行io_service std::thread io_thread([&](){ your_io_service.run(); }); io_thread.detach(); // 发起异步读操作 auto async_read_handler = [this](const boost::system::error_code& ec, std::size_t bytes_read) { if (!ec) { // 处理读取到的数据 process_data(data_buffer, bytes_read); // 继续发起下一次异步读,保持监听 serial_port->async_read_some(ba::buffer(data_buffer), async_read_handler); } }; serial_port->async_read_some(ba::buffer(data_buffer), async_read_handler);
- 配置串口的
额外注意事项
针对你的硬件Redpitaya STEMLAB 125-14,还可以检查以下几点:
- 确保串口设备(比如
/dev/ttyUSB0或对应设备)的权限正确,避免因为权限问题导致异常的读写行为; - 检查Ubuntu 16.04的内核版本,有些旧内核的串口驱动可能也会有类似的问题,可以尝试更新到该版本Ubuntu支持的最新内核。
内容的提问来源于stack exchange,提问作者falopsy
相关产品推荐
相关产品推荐

