c++ barrier 使用详解

108 阅读2分钟

c++ barrier 使用详解

std::barrier c++20

  • 头文件 #include <barrier>
  • 作用:一般被用来协调多个线程,在所有线程都到达屏障点之后,才允许它们继续执行,对于需要线程间同步的并行算法和任务来说非常有用。
  • 使用步骤:
    • 创建 barrier 对象,并指定期待计数;
    • 在线程中调用 arrive 或者 arrive_and_wait 方法,使期待计数减一;
    • 当期待计数减为 0 后,即代表所有线程都已到达屏障点,barrier 会解除所有阻塞在屏障点上的线程并重置期待计数。
  • 注意事项:
    • 不同于 latch ,barrier 可重用;
    • 同时调用 barrier 的成员函数,除了析构函数,不引入数据竞争;
    • 在同一个线程中,可以多次减少期待计数;

std::barrier 成员函数

  • arrive:到达屏障并减少期待计数。
  • wait:阻塞当前线程,直至期待计数减为 0。
  • arrive_and_wait:到达屏障并把期待计数减少一,然后阻塞直至期待计数减为 0。
  • arrive_and_drop:到达屏障并把期待计数减少一并使后续阶段的初始期待计数减一。

使用示例

  • 线程 1 和 线程 2 先各自执行一些任务,然后在屏障点上等待直到所有线程抵达后再继续执行后续代码:

    #include <cstdio>
    #include <thread>
    #include <vector>
    #include <barrier>
    
    using namespace std::literals;
    
    constexpr int num_threads = 2;
    std::barrier barrier(num_threads);
    std::vector<int> v1;
    std::vector<int> v2;
    
    void f1()
    {
        for (int i = 0; i < 2; i++) {
            v1.push_back(i);
            // 到达屏障点并阻塞
            barrier.arrive_and_wait();
            // 所有线程都到达屏障点后,继续执行
            printf("v2[%d] = %d\n", i, v2[i]);
        }
    }
    
    void f2()
    {
        for (int i = 0; i < 2; i++) {
            v2.push_back(i);
            // 到达屏障点并阻塞
            barrier.arrive_and_wait();
            // 所有线程都到达屏障点后,继续执行
            printf("v1[%d] = %d\n", i, v1[i]);
        }
    }
    
    
    int main()
    {
        std::jthread t1(f1);
        std::jthread t2(f2);
        return 0;
    }