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

为何静态std::barrier可用,动态shared_ptr实现却挂起?附可用代码

std::barrier动态(shared_ptr)版本挂起原因分析及修复

问题背景

我编写了两段用std::barrier{2}同步2个线程的C代码:静态创建barrier的版本能正常运行,但最初用std::shared_ptr动态创建的版本会出现挂起问题。由于线程数(即barrier的计数)只能在运行时确定,无法静态声明,因此必须采用动态实现方式。编译运行命令为:clang++-15 -l pthread --std=c++20 demo.cpp && ./a.out(也使用过g-11)。

挂起原因分析

静态版本正常是因为barrier对象的生命周期贯穿整个程序运行,线程调用arrive_and_wait()时对象始终有效。而最初的动态版本挂起,最常见的原因是barrier对象在线程完成等待前被提前销毁:

  • 如果用shared_ptr时,线程捕获的是barrier的引用而非副本,主线程若提前释放shared_ptr(比如调用reset()或让其离开作用域),会导致barrier的引用计数归0,对象被析构。此时线程访问已销毁的barrier,触发未定义行为,表现为挂起或程序崩溃。
  • 另一种可能是运行时确定的线程数与barrier初始计数不匹配:比如实际启动的线程数少于barrier计数,会导致已启动的线程永远等待足够的到达信号;若线程数多于计数,多余线程的arrive_and_wait()也会挂起。

错误示例(导致挂起的代码)

#include <barrier>
#include <thread>
#include <memory>

int main() {
    auto barrier = std::make_shared<std::barrier<>>(2);
    
    // 线程捕获barrier的引用,主线程若提前释放,会访问无效对象
    std::thread t1([&]() {
        barrier->arrive_and_wait();
    });
    
    std::thread t2([&]() {
        barrier->arrive_and_wait();
    });
    
    // 错误:主线程提前重置shared_ptr,导致barrier被销毁
    barrier.reset();
    
    t1.join();
    t2.join();
    return 0;
}

修复后的正确动态版本

#include <barrier>
#include <thread>
#include <memory>

int main() {
    auto barrier = std::make_shared<std::barrier<>>(2);
    
    // 线程捕获shared_ptr副本,保证持有引用,barrier不会被提前销毁
    std::thread t1([barrier]() {
        barrier->arrive_and_wait();
    });
    
    std::thread t2([barrier]() {
        barrier->arrive_and_wait();
    });
    
    t1.join();
    t2.join();
    return 0;
}

额外注意事项

  • 确保运行时确定的线程数与barrier的初始计数完全一致,避免因计数不匹配导致的挂起。
  • 若使用barrier的完成阶段(completion step),需确保该阶段不会抛出未捕获的异常,否则可能触发未定义行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 05:15:31