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

61 lines
2.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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](src/public/libcmd/src/my_cmd.cpp#L107))中读取 stdin 的代码:
```c
if (read(STDIN_FILENO, &c, 1) == -1) return -1;
```
只检查了 `-1`(错误),未处理返回 `0`EOF。当进程无真正控制终端时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_send``pthread_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](src/public/libcmd/src/my_cmd.cpp) | `read()` EOF 处理;`enableRawMode()` 返回值检查 |
| [app_cmd.cpp](src/system/RTU/src/app_cmd.cpp) | 非阻塞 `cmd_recv_nonblock()``isatty` + `select`;移至 EV_TIMER2 |
| [CLAUDE.md](CLAUDE.md) | 全文翻译为中文 |