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

std::counting_semaphore计数器为0时调用acquire()的问题及编译器推荐

std::counting_semaphore计数器为0时调用acquire()的行为分析

问题核心

当std::counting_semaphore的计数器值被减至0后,若有其他线程调用acquire(),会触发什么行为?结合下方示例代码,线程t1将计数器降至0后,线程t3调用acquire()导致程序陷入永久阻塞,表现为“处理超时”,以下是具体分析。

示例代码

#include <iostream>
#include <semaphore>
#include <thread>
#include <vector>

std::vector<int> myVec{};
std::counting_semaphore<2> signal(1);

void addElement() 
{
    std::cout << "In addElement() \n";
    myVec.insert(myVec.end(), {0, 1, 0, 3});
    std::cout << "Sender: Element added ."  << '\n';
    std::cout << "In addElement() value1 :" << signal.max() << "\n";
    signal.release();    
}

void accessElement() 
{
    std::cout << "Waiter:: Waiting for data accessing." << '\n';
    std::cout << "In accessElement() value1 :" << signal.max() << "\n";
    signal.acquire();
    std::cout << "updated the element........." << '\n';
}

int main() 
{
    std::thread t1(accessElement);
    t1.join();
    std::thread t3(accessElement);
    t3.join();
    std::thread t2(addElement);
    t2.join();
}

行为分析

  1. 信号量初始化:示例中signal是最大许可数为2的计数信号量,初始计数器值为1。

  2. 线程执行顺序与阻塞原因:

    • 主线程先启动t1并调用join(),t1执行accessElement()时调用signal.acquire(),计数器从1减至0,t1完成后退出。
    • 接着主线程启动t3并调用join(),t3执行accessElement()时再次调用signal.acquire()——此时计数器已经是0,根据std::counting_semaphore的规则,acquire()会阻塞当前线程,直到有其他线程调用release()使计数器大于0。
    • 但主线程要等t3执行完成才会启动t2,而t2是唯一会调用signal.release()的线程,这就形成了死锁:t3阻塞等待计数器增加,t2永远没机会启动来释放信号量,最终程序陷入永久阻塞,表现为“处理超时”。
  3. acquire()的标准行为:

    • 当计数器值>0时,acquire()会原子性地将计数器减1,线程立即继续执行;
    • 当计数器值=0时,调用acquire()的线程会被挂起,进入阻塞状态,直到有其他线程调用release()(每次release()会将计数器加1,最大不超过信号量的许可上限),线程才会被唤醒并执行计数器减1操作。

推荐在线编译器

可用于测试此类多线程示例的在线工具包括:

  • 编译器资源管理器(Compiler Explorer):支持C++20及以上标准,能查看编译后的汇编代码,同时支持运行多线程程序观察行为
  • 在线GDB调试器(Online GDB):支持设置断点、单步调试,便于追踪线程阻塞的具体位置
  • CPP.sh:轻量便捷,可快速编译运行C++代码,适合快速验证多线程逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 14:00:47