C++ C++;这个MPMC队列中的原子需要什么内存顺序?

C++ C++;这个MPMC队列中的原子需要什么内存顺序?,c++,C++,这是我仅使用原子实现的无锁、无等待、多线程安全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:

这是我仅使用原子实现的无锁、无等待、多线程安全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;
    }
};
模板
类队列{
tar[大小];
std::原子电路64 t启动;
std::原子uint64终端;
std::原子int32预计数;
标准::原子计数;
公众:
队列_mpmc(){
开始=0;
结束=0;
预计数=0;
后计数=0;
}
布尔特里普什(T数据){
int32_t c=++precount;//这必须在行开始之前完成
如果(c>大小){[[不太可能]]
--预计数;
返回false;
}
ar[end++%SIZE]=数据;
++postcount;//这必须在行开始后执行
返回true;
}
T trypop(){
int32_t c=--postcount;//这必须在行开始之前完成
if(c<0){
++后计数;
返回T{};
}
tr=ar[start++%SIZE];
--precount;//这必须在行开始后执行
返回r;
}
int32_t len(){
返回预计数;
}
};
它的大小设计为2(32、64、128、256等),因为在这些情况下,由于编译器优化,它使用模运算符在底层数组上提供了有效的环绕

我一直在读关于原子的书,但我对这是一个新手,我不知道这是否适用于我正在使用的原子?设计依赖于
++/--precount
++/--postcount
end++
start++
指令之前或之后(在
ar
开头的行中)。尽管如此,这只需要应用于当前线程,它不需要在线程之间进行超出原子学通常预期的同步


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

如果其他错误已修复,则最有可能的是
开始
结束
,以及
预计数
在所有使用中都可以释放内存顺序

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

因此,
postcount
需要在push中释放内存顺序(“发布”),并在读取之前获取内存顺序(即在pop中)


可能。

两个线程同时推送,第一个线程结束+,因此将填充ar[0]。第二个执行end++,得到ar[1]。第二个线程首先完成,增加后计数。第一个线程尚未填充ar[0]。现在出现了一条读者线索。查看postcount>0,读取ar[0],其中实际上没有t。在担心内存顺序之前,可能先解决这个问题。另外,理论上,如果一个生产者在end++之后暂停太久,以至于其他线程导致队列环绕到同一位置,那么至少两个生产者可以写入同一位置。@tony,这是一个困难的问题(第一个),有什么建议吗?有没有办法确保线程在重新调度之前完成一定量的执行?关于无锁的问题是,你不能保证/保证任何事情。