协作取消

内容介绍

C++ 没有安全的“强杀线程”标准 API。线程退出应由任务自己检查停止信号,然后主动结束。

C++20 提供 std::jthreadstd::stop_token,可以表达协作式取消。取消能力的性能意义是:任务停止时不拖住线程池,不让无用任务继续占用工作线程。

jthread + stop_token

#include <chrono>
#include <iostream>
#include <thread>
 
using namespace std::chrono_literals;
 
int main() {
    std::jthread worker([](std::stop_token st) {
        while (!st.stop_requested()) {
            std::cout << "working\n";
            std::this_thread::sleep_for(100ms);
        }
        std::cout << "stopped\n";
    });
 
    std::this_thread::sleep_for(350ms);
    worker.request_stop();
}

std::jthread 析构时也会请求停止并等待线程结束。

C++11/17 停止标志

std::atomic<bool> stop = false;
 
std::thread worker([&] {
    while (!stop.load()) {
        // do work
    }
});
 
stop.store(true);
worker.join();

最佳代码实践

  • 长循环任务必须设计停止条件。
  • 阻塞等待任务要能被唤醒退出,例如关闭 Channel 或 notify_all
  • C++20 优先用 std::jthreadstop_token
  • C++17 及以前使用 atomic<bool> 或关闭队列表达停止。

常见错误用法

while (true) {
    do_work();
}

问题:线程没有退出路径,程序关闭时只能泄漏、卡住或强制终止。

worker.detach();
// 希望进程退出时后台线程自己安全结束

问题:detach 后生命周期不可控,通常不是工程级退出方案。

注意事项

  • 取消是协作式的:请求停止不等于立即停止。
  • 如果线程卡在不可中断 IO,stop_token 本身无法把它唤醒。
  • 关闭队列、条件变量通知、超时等待经常要和取消信号配合使用。

学习路径

  • 上一节:cpp线程池
  • 当前阶段:cpp多线程
  • 暂时终点