
TKeed 调试实录无任务时 CPU 为何飙到 90%一个条件变量 bug 的完整排查过程【免费下载链接】TKeed High Performance HTTP WebServer项目地址: https://gitcode.com/gh_mirrors/tk/TKeedTKeed 是一个基于 Reactor 模型的高性能 HTTP WebServer采用 epoll 非阻塞 I/O 线程池实现。在一次压测中我们发现服务器空闲时 CPU 占用率长期接近满负荷压测时反而降到 85% 左右——这显然不正常。本文完整复盘这个条件变量 bug 的排查与修复过程帮你理解 worker 线程为何会空转以及修复后 CPU 从 90% 降到 10% 的验证结果。问题现象没活干CPU 却跑满 90%先交代一下 TKeed 的并发模型理解背景后这个 bug 才更直观主线程监听线程负责 epoll 事件循环一旦有客户端请求到达就把任务封装成 task 丢进线程池并pthread_cond_signal唤醒 worker 线程执行worker 线程在没任务时必须阻塞在条件变量上有任务才干活。问题现象很反直觉无任务时CPU 占用率一直接近满负荷压测时CPU 占用率反而略微下降约 85%。经验告诉我们CPU 利用率长期高于 90%几乎一定是死循环在作怪。排查过程一先排除主事件循环主循环在 src_code/main.c 中tk_epoll_wait的 timeout 参数动态计算通常设为 -1 或最小定时器的剩余时间理论上无事件时应一直阻塞。我们用strace跟踪系统调用确认epoll_wait确实阻塞住了——但 CPU 占用率依旧很高。再进一步注释掉主循环体CPU 占用率还是 90% 以上。结论问题不在 epoll 主循环而在线程池。排查过程二top -H 定位到 worker 线程关键时刻一条命令就指明了方向top -H -p pid可以看到 4 个 worker 线程 CPU 使用率都在25% 左右4 × 25% ≈ 100%。线程池里的 worker 在轮询而不是等待这就是典型的条件变量没生效。TKeed 的整体调用关系可以对照下面的调用树图重点关注threadpool.c中的threadpool_worker根本原因一个写反的逻辑与翻出线程池 worker 的最外层循环src_code/threadpool.c 中threadpool_worker当时的写法是while ((pool-queue_size 0) (pool-shutdown)) { pthread_cond_wait((pool-cond), (pool-lock)); }本意是任务队列为空且未停机 → 阻塞等待。但有两个致命错误忘了 shutdown 初始值为 0即未停机条件永远不成立pthread_cond_wait一次都不会被调用逻辑关系本身也反了——阻塞条件应该是队列为空且未 shutdown即!(pool-shutdown)。结果worker 线程拿到锁 → 判断不满足 → 直接解锁 → 继续循环 → 再抢锁……一个高频空轮询死循环4 个 worker 就把 4 个核打满了。修复方案一行取反修复后的阻塞判断为while ((pool-queue_size 0) !(pool-shutdown)) { pthread_cond_wait((pool-cond), (pool-lock)); }现在队列为空且未停机时pthread_cond_wait会自动释放锁并挂起线程直到threadpool_add插入任务后调用pthread_cond_signal被唤醒停机信号pthread_cond_broadcast也能正常打断等待。修复验证满负荷 CPU 降到 10% 左右重新编译压测Webbench60s1000 并发8 workertop观察各线程 CPU修复后单线程约 5%、主线程约 8%满负荷下总 CPU 占用率约 40%8 线程 × 5%空闲时 CPU 基本归零。更多压测数据4/8 工作线程吞吐对比、1KB 标准页面测试可参考 测试及改进.md条件变量、epoll 超时等设计细节见 启示录.md 与 并发模型.md。给新手的 4 条避坑清单条件变量的等待条件要复查初值while (!cond)里用到的每个变量如shutdown都要确认初始化后cond_wait真的能被触发警惕轮询代替等待worker 空闲却持续抢锁就是pthread_cond_wait没执行的典型症状善用top -H -p pid线程级 CPU 视图是定位哪几个线程在空转最快的工具strace 确认阻塞点后继续缩小范围主循环阻塞 ≠ 系统无 CPU 消耗其他线程仍可能是元凶。这次 bug 本质是一个逻辑取反错误但它生动演示了 Linux 线程池同步的精髓互斥锁保证互斥条件变量负责睡下与叫醒——睡不下的线程就会把整台机器烧到 90%。【免费下载链接】TKeed High Performance HTTP WebServer项目地址: https://gitcode.com/gh_mirrors/tk/TKeed创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考