You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何此ThreadPool在析构时死锁?如何基于std::barrier修复?

C++20 std::barrier线程池死锁问题分析与修复

问题根源

死锁的核心原因是析构函数执行顺序错误,以及子线程收到停止请求时未正确处理std::barrier的计数:

  1. 原析构函数先唤醒子线程(设置start并notify_all),再请求线程停止。这导致子线程被唤醒后,未检测到停止信号就进入任务处理流程,最终卡在sync_point.arrive_and_wait(),等待主线程到达屏障。
  2. 主线程此时正在等待子线程join,不会再调用arrive_and_wait(),形成循环等待的死锁。
  3. 额外风险:析构时子线程执行任务逻辑时,task指针可能已失效,触发未定义行为。

保留std::barrier的小幅修改方案

只需调整析构顺序并修正子线程的屏障处理逻辑,即可解决问题:

1. 调整析构函数的执行顺序

先请求线程停止,再唤醒等待的子线程,避免子线程进入无效的任务流程:

ThreadPool::~ThreadPool() {
    // 先请求所有线程停止
    for (auto& t : threads) {
        t.request_stop();
    }
    // 唤醒所有等待start的线程
    start.test_and_set();
    start.notify_all();
    // 等待线程退出
    for (auto& t : threads) {
        t.join();
    }
}

2. 修正子线程的屏障与停止逻辑

子线程被唤醒后立即检查停止请求,若已触发停止,通过arrive_and_drop()退出屏障阶段(避免其他线程等待);任务执行中也加入停止检查,确保及时响应:

void ThreadMain(std::stop_token stoken, ThreadPool* pool) {
    while (!stoken.stop_requested()) {
        pool->start.wait(false);
        
        // 被唤醒后优先检查停止请求
        if (stoken.stop_requested()) {
            pool->sync_point.arrive_and_drop();
            return;
        }

        int i{0};
        while ((i = pool->idx.fetch_sub(1) - 1) > -1) {
            (*(pool->task))(pool->ctx, i);
            // 任务执行中也响应停止请求
            if (stoken.stop_requested()) {
                break;
            }
        }

        // 根据停止状态选择屏障操作
        if (!stoken.stop_requested()) {
            pool->sync_point.arrive_and_wait();
        } else {
            pool->sync_point.arrive_and_drop();
            return;
        }
    }
}

3. 原代码其他可优化点(可选)

  • 任务指针task和上下文ctx可改用std::atomic指针,避免析构时的竞态访问;
  • 屏障的完成函数可保留原逻辑,确保start标志正确清空:
    sync_point(num_threads, [&]() noexcept { this->start.clear(); })
    

验证说明

修改后重新编译运行:

g++ main.cpp -O0 -g --std=c++20

线程池析构时,子线程会正确响应停止请求,通过arrive_and_drop()减少屏障计数,不会卡在等待主线程的状态,主线程可正常完成join,死锁问题解决。

内容的提问来源于stack exchange,提问作者fabian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 18:50:54