RTU/claude/mid/app_cmd_CPU108问题修复.md

2.6 KiB
Raw Blame History

app_cmd 线程 CPU 108% 问题修复

日期

2026-06-12

背景

app_cmd 线程是 CLI 命令行处理线程,属于 9 个应用线程之一。其主循环采用定时器驱动的事件模型EV_TIMER1=10ms、EV_TIMER2=100ms、EV_TIMER3=1000ms。原本 cmd_recv() 在 EV_TIMER1 中每次被调用,但该调用已被注释掉,原因是启用后 CPU 占用飙升至 108%。

根因

直接原因:read() 返回 EOF 未处理

linenoiseEdit()my_cmd.cpp:107)中读取 stdin 的代码:

if (read(STDIN_FILENO, &c, 1) == -1) return -1;

只检查了 -1(错误),未处理返回 0EOF。当进程无真正控制终端时RTU 嵌入式部署环境常见stdin 处于 EOF 状态,read() 立即返回 0。代码不匹配 -1,继续执行,c 为未定义值,后落入 buf[len++] = c 分支,循环回 read() — 死循环CPU 100%+。

架构层面问题

问题 说明
阻塞 I/O 在定时器线程中 linenoise() 是同步阻塞调用,放在 10ms 定时器中导致线程被阻塞
无 stdin 就绪检查 没有用 select()/poll() 先检查 stdin 是否有数据
终端模式反复切换 每次 linenoise() 调用都 tcgetattr+tcsetattr,频率过高
tcsetattr 返回值未检查 linenoise() 中调用 enableRawMode() 未检查返回值

定时器机制

定时器使用 POSIX timer_create(CLOCK_REALTIME, SIGEV_THREAD, ...),每次超时内核创建新线程执行回调 → task_event_sendpthread_cond_signal 唤醒 app 线程。

修复内容

1. my_cmd.cpp — 修复 EOF 处理和返回值检查

  • read() 返回值判断从 == -1 改为 <= 0,覆盖 EOF 场景
  • linenoise() 中检查 enableRawMode() 返回值,失败直接返回 NULL避免在有问题的终端上执行读取循环

2. app_cmd.cpp — 重构为非阻塞模式

  • 新增 isatty(STDIN_FILENO) 前置检查,非终端环境直接跳过
  • select() 零超时检测 stdin 可读性,仅在数据就绪时才调用 linenoise()
  • 从 EV_TIMER110ms移至 EV_TIMER2100ms降低终端模式切换频率

验证

  • 编译:零错误零警告
  • 测试:./test/RTU < /dev/null 运行 3 秒CPU 占用 0.0%(修复前为 108%

影响文件

文件 改动
my_cmd.cpp read() EOF 处理;enableRawMode() 返回值检查
app_cmd.cpp 非阻塞 cmd_recv_nonblock()isatty + select;移至 EV_TIMER2
CLAUDE.md 全文翻译为中文