首页 > 解决方案 > C++ 这个 MPMC 队列中的原子需要什么内存顺序?

问题描述

这是我仅使用原子实现的无锁、无等待、多线程安全的 MPMC 队列:

template <typename T, int32_t SIZE>
class queue_mpmc {
    T ar[SIZE];
    std::atomic_uint64_t start;
    std::atomic_uint64_t end;
    std::atomic_int32_t precount;
    std::atomic_int32_t postcount;
  public:
    queue_mpmc() {
        start = 0;
        end = 0;
        precount = 0;
        postcount = 0;
    }
    bool trypush(T data) {
        int32_t c = ++precount;    // this must be done before the line beginning ar
        if (c > SIZE) { [[unlikely]]
            --precount;
            return false;
        }
        ar[end++ % SIZE] = data;
        ++postcount;               // this must be done after the line beginning ar
        return true;
    }
    T trypop() {
        int32_t c = --postcount;   // this must be done before the line beginning ar
        if (c < 0) {
            ++postcount;
            return T{};
        }
        T r = ar[start++ % SIZE];
        --precount;                // this must be done after the line beginning ar
        return r;
    }
    int32_t len() {
        return precount;
    }
};

它被设计为 SIZE 的 2 倍(32、64、128、256 等),因为在这些情况下,由于编译器优化,它使用模运算符提供了对底层数组的有效环绕。

我一直在阅读有关 atomic memory order的内容,但我对此并不陌生,我无法弄清楚这是否适用于我正在使用的 atomics?该设计确实依赖于++/--precountand在and指令++/--postcount之前或之后(位于开头的行内)。就是这样,并且只需要应用于当前线程,它不需要在线程之间同步超出通常预期的原子。end++start++ar

我可以通过指定内存顺序来提高性能吗?

标签: c++

解决方案


如果其他错误已修复,则很可能 start,endprecount在所有用途中都可以是 memory_order_relaxed 。

postcount是表示一个值已写入队列的变量。即它控制值的发布和值的读取

所以postcount在推送中需要memory_order_release(“发布”),在读取之前需要memory_order_acquire(即在pop中)。

也许。


推荐阅读