线程池复用一组工作线程执行许多短任务,避免“每来一个任务就创建/销毁一个线程”的栈、TLS、调度和生命周期成本。但线程池不是一个 std::vector<std::thread>:它至少要定义任务队列、唤醒条件、结果/异常传递、任务容量、停止语义和任务提交后谁负责背压。大多数生产事故都出在停止与过载,而不在 worker 循环本身。
一个可靠线程池的状态机
运行状态中接受任务、worker 等待条件变量;关闭开始后拒绝新任务或明确走降级队列;已有任务可以选择 drain 完成,也可以取消未开始任务;最后唤醒所有 worker 并 join。这些策略必须对调用者可见,否则析构时任务“有时执行有时丢失”会成为难以复现的 bug。
worker 循环最小模式
1 | for (;;) { |
谓词等待防止虚假唤醒;锁只保护队列,不应覆盖任务执行;任务抛出的异常应被 packaged_task/future 或明确捕获处理。实际实现还需要处理提交与关闭的竞争、队列上限、任务优先级和统计信息。
线程数不是“越多越快”
CPU 密集任务通常接近可用核心数,过多线程会增加上下文切换和 cache 争用;I/O 密集任务可根据等待比例增加并发,但也要受 fd、内存和下游服务能力限制。对于实时控制,线程池通常只适合后台解析、日志和预计算,控制线程不应把 deadline 交给一个可能被队列拥塞的通用 worker。
work stealing、优先级队列和动态伸缩都是进一步优化,不是第一版必需品。先实现有界队列、可测试的停止协议和明确的过载行为,再通过 profiler 判断锁竞争或队列是否真是瓶颈。