一种用于多线程中间状态同步的屏障机制

一种用于多线程中间状态同步的屏障机制

为了解决在多线程环境中,需要一个内置的计数屏障对于多个线程中的某一个部分进行检查,确保所有线程均到达该点后才能继续执行。

该屏障常被用于多线程流水线中的中间检查,适用于阶段分割,是一种有效的同步机制。

此处构建了一个barrier类,其中arrive_and_wait()函数是对应的屏障方法,work是测试线程。

此处代码注释掉的是使用busy-wait进行循环的忙等版本,保留了使用条件变量和unique_lock的阻塞wait_for版本,可以对比两者之间的性能差距。

一般来说,线程规模较小,任务量较少时busy-wait效率较高,是由于sleep-awake过程中有系统调用。当任务规模达到一定程度时,wait_for通常性能较好。

代码如下:

复制代码
#include <thread>
#include <unistd.h>
#include <vector>
#include <cstddef>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include "barrier.hpp"

class barrier {
public:

    barrier(size_t expected)
    :_expected(expected)
    ,_arrived(0)
    ,_passed(0)
    {}

    void arrive_and_wait();

private:
    const size_t _expected;
    std::atomic<size_t> _arrived;
    std::atomic<size_t> _passed;
    std::mutex mtx;
    std::condition_variable cv;
};

/*void barrier::arrive_and_wait()
{
    auto passed = _passed.load();
    if (_arrived.fetch_add(1) == _expected - 1) {
        // NOTE: reset *before* incrementing, otherwise we might reset to zero a
        // thread already waiting on the next wave
        _arrived = 0;
        _passed++;
    } else {
        while (_passed.load() == passed) {
        // busy-wait
        }
    }
}*/

void barrier::arrive_and_wait()
{
    auto passed = _passed.load();
    if (_arrived.fetch_add(1) == _expected - 1) {
        // NOTE: reset *before* incrementing, otherwise we might reset to zero a
        // thread already waiting on the next wave
        _arrived = 0;
        _passed++;
        cv.notify_all();
    } else { //block
        std::unique_lock<std::mutex> lck(mtx);
        cv.wait(lck, [&] {
            return _passed.load() != passed;
        });
        lck.unlock();
        cv.notify_all();
    }
}

void work(size_t id, barrier& b)
{
    printf("+%ld\n", id); fflush(stdout);
    b.arrive_and_wait();
    printf(".%ld\n", id); fflush(stdout);
    b.arrive_and_wait();
    printf("-%ld\n", id); fflush(stdout);
}

int main(int argc, char** argv)
{
    auto nthreads = atoi(argv[1]);
    barrier b(nthreads);
    std::vector<std::thread> threads;

    for (auto i = nthreads; i; i--) {
        threads.emplace_back(work, i, std::ref(b));
    }

    for (auto& thread : threads) {
        thread.join();
    }
}
相关推荐
charlie1145141913 分钟前
计算机图形学速通指南笔记(0)
c++·笔记·软件工程·计算机图形学·工程实践
带土112 分钟前
2. C++ private、protected、public
开发语言·c++
星火开发设计1 小时前
二维数组:矩阵存储与多维数组的内存布局
开发语言·c++·人工智能·算法·矩阵·函数·知识
夜勤月2 小时前
彻底终结内存泄漏与悬挂指针:深度实战 C++ 智能指针底层原理与自定义内存池,打造稳如泰山的系统基石
开发语言·c++
Fcy6482 小时前
⽤哈希表封装unordered_map和unordered_set(C++模拟实现)
数据结构·c++·散列表
CSDN_RTKLIB2 小时前
右值引用一个误区
c++
一分之二~2 小时前
二叉树--层序遍历(迭代和递归)
数据结构·c++·算法·leetcode
zhooyu3 小时前
OpenGL 与 C++:深入理解与实现 Transform 组件
开发语言·c++
东方轧线3 小时前
突破锁竞争的性能枷锁:深度剖析 C++ 内存模型与无锁编程在超大规模并行 AI 系统中的极致应用实践
java·c++·人工智能
Word码4 小时前
[C++语法]-string类(用法详解及实现)
开发语言·c++