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

请求用std::condition_variable实现latch的arrive_and_wait(C++17环境)

用C++17实现Latch的arrive_and_wait方法(替代忙等)

问题背景

项目基于C17开发,无法使用C20的std::latch,需要用std::condition_variable实现arrive_and_wait方法,替换原代码中的忙等循环,确保"done 1""done 2""done 3"能同时输出。

修改后的完整代码

#include <atomic>
#include <condition_variable>
#include <limits>
#include <chrono>
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <future>
#include <thread>

class Latch
{
public:
    Latch(void) : expected(0) {}

    void count_up(void)
    {
        if(expected < std::numeric_limits<Count>::max())
            expected++;
        else
        {
            std::cerr<<"#Error! Latch::count_up: expected: "<<expected<<std::endl;
            exit(EXIT_FAILURE);
        }
    }

    void arrive_and_wait(void)
    {
        // 原子操作减少计数,获取减之前的值
        auto current = expected--;
        
        // 不是最后一个到达的线程,进入等待
        if (current > 1) {
            std::unique_lock<std::mutex> lock(mutex);
            // 带条件等待,避免虚假唤醒
            cond.wait(lock, [this]{ return expected.load() == 0; });
        } 
        // 最后一个到达的线程,唤醒所有等待线程
        else if (current == 1) {
            std::lock_guard<std::mutex> lock(mutex);
            cond.notify_all();
        }
    }

private:
    using Count = uint_fast8_t;
    std::atomic<Count> expected;
    std::condition_variable cond;
    // 新增互斥锁,与condition_variable配合保证线程安全
    std::mutex mutex;
};

void Run(const int delayInSeconds, Latch * const latch=nullptr)
{
    if(latch) latch->count_up();
    std::this_thread::sleep_for( std::chrono::seconds(delayInSeconds) );
    if(latch) latch->arrive_and_wait();
}

int main(void)
{
    std::cout<<"start...\n";

    Latch latch;
    auto f1 = std::async(Run, 2, &latch);
    auto f2 = std::async(Run, 4, &latch);
    auto f3 = std::async(Run, 8, &latch);

    f1.get(); std::cout<<"done 1\n";
    f2.get(); std::cout<<"done 2\n";
    f3.get(); std::cout<<"done 3\n";

    return EXIT_SUCCESS;
}

关键修改说明

  • 新增互斥锁:std::condition_variable必须与std::mutex配合使用,避免竞态条件和虚假唤醒问题,保证线程安全。
  • 原子计数操作:expected为原子变量,expected--是原子操作,确保多线程环境下计数修改的正确性。
  • 等待与唤醒逻辑:
    • 非最后到达的线程会进入等待状态,直到计数变为0;
    • 最后一个到达的线程负责唤醒所有等待的线程,确保所有线程同时继续执行,实现预期的同步效果。
  • 防虚假唤醒:cond.wait使用带条件的重载,每次被唤醒都会检查expected是否为0,避免因系统虚假唤醒导致的错误执行。

内容的提问来源于stack exchange,提问作者S.V

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 07:15:26