C++request_stop主动请求停止

2026-03-22 19:00:31 1387阅读

C++20 request_stop():主动请求线程停止的现代协程与异步控制机制

在现代C++并发编程中,如何安全、优雅地终止正在运行的线程或异步任务,始终是一个关键挑战。C++20 引入了标准化的协作式取消机制——std::stop_tokenstd::stop_sourcestd::stop_callback,其中 request_stop()std::stop_source 提供的核心成员函数,用于主动发起停止请求。它不强制终止线程,而是向所有关联的 stop_token 发送信号,由接收方自主决定是否响应、何时响应以及如何清理资源。这种“协作式”设计显著提升了程序的健壮性与可预测性,避免了传统 std::thread::interrupt() 或信号杀线程等粗暴方式带来的资源泄漏与状态不一致风险。

request_stop() 的本质是原子地设置一个内部停止状态,并唤醒所有等待该状态变更的同步点(如 stop_token::wait())。一旦调用成功,所有后续对 stop_token::stop_requested() 的查询将返回 true,且已注册的 stop_callback 将被同步执行(若在同一线程调用)或异步调度(取决于实现)。值得注意的是,request_stop() 本身是幂等的:重复调用不会产生额外副作用,仅首次调用生效。

以下是一个典型的应用场景:一个长期运行的工作线程需支持外部中断。我们通过 std::jthread(C++20 新增的“可自动加入的线程”)封装逻辑,其构造时自动关联 std::stop_source,并可通过 get_stop_token() 获取对应令牌:

#include <iostream>
#include <thread>
#include <chrono>
#include <stop_token>

void worker(std::stop_token stoken) {
    std::cout << "Worker started.\n";

    // 模拟周期性工作,每次检查是否被请求停止
    for (int i = 0; i < 10; ++i) {
        if (stoken.stop_requested()) {
            std::cout << "Stop requested at iteration " << i << ", exiting gracefully.\n";
            return;
        }

        std::cout << "Working... iteration " << i << "\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(300));
    }

    std::cout << "Worker completed normally.\n";
}

int main() {
    std::jthread t{worker};

    // 主线程等待一段时间后主动请求停止
    std::this_thread::sleep_for(std::chrono::seconds(2));
    t.request_stop(); // 关键调用:主动触发停止信号

    // jthread 析构时会自动 join,确保 worker 已退出
    std::cout << "Main thread finished.\n";
}

上述代码中,t.request_stop()std::jthread 提供的便捷接口,其内部调用所持 std::stop_sourcerequest_stop() 方法。worker 函数持续轮询 stoken.stop_requested(),一旦检测到信号即提前退出,完成资源清理(如关闭文件、释放内存、注销回调等),实现零竞态的优雅终止。

更精细的控制可通过手动管理 stop_source 实现。例如,在异步 I/O 或长时间阻塞操作中,常需结合 stop_callback 实现“唤醒阻塞点”:

#include <iostream>
#include <thread>
#include <stop_token>
#include <mutex>
#include <condition_variable>

void blocking_worker(std::stop_token stoken) {
    std::mutex mtx;
    std::condition_variable cv;
    bool ready = false;

    // 注册回调:当 stop 被请求时,唤醒条件变量
    std::stop_callback cb{stoken, [&]{
        std::lock_guard<std::mutex> lock{mtx};
        ready = true;
        cv.notify_one();
    }};

    std::cout << "Blocking worker started.\n";

    while (!stoken.stop_requested()) {
        std::unique_lock<std::mutex> lock{mtx};
        cv.wait(lock, [&]{ return ready || stoken.stop_requested(); });

        if (stoken.stop_requested()) {
            std::cout << "Exit due to stop request.\n";
            return;
        }

        // 执行实际工作...
        std::cout << "Processing...\n";
        ready = false;
    }
}

int main() {
    std::stop_source src;
    std::thread t{blocking_worker, src.get_token()};

    std::this_thread::sleep_for(std::chrono::seconds(1));
    src.request_stop(); // 直接调用 stop_source 的 request_stop

    t.join();
}

此处 std::stop_callback 确保了即使线程处于 cv.wait() 阻塞状态,也能被及时唤醒并响应停止请求,避免了传统 pthread_cancel 的不可靠性与平台依赖性。

需要强调的是,request_stop() 并非万能开关。它要求所有参与方遵循协作规范:工作函数必须定期轮询 stop_token,阻塞操作需配合 stop_callback 或支持可中断等待(如 std::condition_variable::wait_until 配合 stop_token)。此外,request_stop() 不保证立即生效——它只改变状态并通知,具体响应时机由业务逻辑控制,这恰是其安全性的根基。

总结而言,request_stop() 是 C++20 并发模型走向成熟的重要标志。它将“谁来终止”与“如何终止”解耦,赋予开发者清晰的责任边界:调用方负责发出请求,执行方负责响应与清理。这一机制不仅适用于 std::jthread,也深度融入 std::future协程std::generator)、以及未来标准库的异步抽象中。掌握 request_stop() 的正确用法,是编写高可靠性、易维护 C++ 并发程序的必备技能。在多核与异步成为常态的今天,主动、协作、可预测的停止语义,正逐渐取代强制、独断、易出错的传统方案,成为现代系统编程的新范式。

文章版权声明:除非注明,否则均为Dark零点博客原创文章,转载或复制请以超链接形式并注明出处。

目录[+]