使用无锁指针队列在线程之间移动数据是否安全
Is it safe to move data between threads using a lock less queue of pointers
我已经实现了一个简单的循环缓冲区,使用(Camerons优秀)readerwriterqueue
在线程之间移动数据,以防止在我的应用程序中(取消)分配。代码如下所示:
using ElemPtr = std::unique_ptr<int>;
moodycamel::ReaderWriterQueue<ElemPtr> emptyQueue(10);
moodycamel::ReaderWriterQueue<ElemPtr> dataQueue(10);
LoadQueueWithPointers(emptyQueue);
//If statements removed for brevity
auto producer = [&]() {
ElemPtr ptr;
while (true) {
emptyQueue.try_dequeue(ptr);
LoadData(ptr);
dataQueue.try_enqueue(std::move(ptr));
}
};
//If statements removed for brevity
auto consumer = [&]() {
ElemPtr ptr;
while (true) {
dataQueue.try_dequeue(ptr);
ProcessData(ptr);
emptyQueue.try_enqueue(std::move(ptr));
}
};
std::thread producerThread(producer);
std::thread consumerThread(consumer);
在检查此代码时,在我看来,如果使用者线程在 RAM 中更新数据(指针引用)之前收到指针,则数据可能会损坏。我试图使用延迟、不同的队列长度、不同的数据大小以及通过将线程移动到物理上独立的处理器(套接字)来诱导数据损坏。到目前为止,我没有看到任何数据损坏问题。
因此,我的问题是:到目前为止,我是否很幸运,并且存在等待发生的数据损坏问题,或者moodycamel::ReaderWriterQueue
使用的内存围栏(std::memory_order_acquire
,std::memory_order_release
)是否也保护我的(非原子)内存操作?
TL;DR:只要ReaderWriterQueue<>
的实现使用具有正确内存顺序的原子类型,就可以了。
您需要的内存排序memory_order_release
在编写器端,memory_order_acquire
在读取器端。这些内存顺序意味着,原子写入之前的所有写入都需要首先发生,原子读取之后的所有读取都需要稍后发生。这些其他写入/读取包括您对ElemPtr
后面数据的访问。
由于队列本身需要将数据从一个线程发送到另一个线程,因此它需要在自己的原子元数据上使用完全相同的内存排序,以便能够发送有效负载数据指针。因此,如果正确实现ReaderWriterQueue<>
,您应该是安全的。
相关文章:
- 复制和交换习惯用法与移动操作之间的交互
- 移动语义和深层/浅层复制之间有什么关系?
- 如何在窗口之间移动 std::unique_ptr 而不会冒内存泄漏的风险?
- 在 b2World 之间移动 b2Body
- 玩家移动和碰撞之间的交互问题
- 在'string=string+s1'和"string+=s1"之间移动语义可以保存多少个复制操作?
- 比较C 中移动和智能指针之间的习惯
- C++复制构造函数和移动语义之间的区别
- C++11 在列表到映射(或其他容器)之间移动元素
- 使用无锁指针队列在线程之间移动数据是否安全
- 复制和移动构造函数之间的效率差异
- 将独特的指针移动到脱口机之间
- 在 3 点之间移动模型会导致模型偏离位置
- 在此示例中,移动和前进之间不同
- 在集合之间移动“ unique_ptr”
- 在线程之间移动向量
- 移动赋值运算符和移动构造函数之间的区别
- 有没有一种非重复的方法允许程序员在成员初始化的复制和移动语义之间进行选择
- 在变量之间移动队列而不复制元素
- 如何在两个磁盘的移动之间添加延迟