简体   繁体   English

C ++中多值的多线程原子存储/加载

[英]Multithreaded Atomic Store/Load of multiple values in C++

Suppose I have a structure and class in C++: 假设我在C ++中有一个结构和类:

struct Vec {
   double x;
   double y;
   double z;
}

class VecTracker {
   Vec latest_vec;
   std::atomic<double> highest_x;
   std::atomic<double> highest_y;
   std::atomic<double> highest_z;

   //updates highest_x, highest_y, highest_z atomically
   void push_vec(const Vec& v);
   double get_high_x() const;
   double get_high_y() const;
   double get_high_z() const;
   //returns Vec consisting of snapshot of highest_x, highest_y, highest_z
   Vec get_highs() const;
}

I'll have R reader threads and one writer thread. 我将有R个读者线程和一个作家线程。 The writer thread will update zero or more of the highest_* members. highest_*线程将更新零个或多个highest_*成员。 If the reader thread calls get_highs() I need all the writes from the current invocation of the writer thread's push_vec() function to be visible to the reader thread before the reader thread reads highest_x , highest_y , etc. to produce a vector. 如果读取器线程调用get_highs() ,则在读取器线程读取highest_xhighest_y等产生矢量之前 ,我需要写入器线程的push_vec()函数当前调用的所有写入对读取器线程都是可见的。

Now, I know that if Vec is sufficiently small, I could just use a std::atomic<Vec> . 现在,我知道如果Vec足够小,我可以使用std::atomic<Vec> Problem is, if it's too big, native CPU instructions for these store/loads can't be used. 问题是,如果太大,则无法使用这些存储/加载的本机CPU指令。 Is there any way to use std::atomic_thread_fence to guarantee that multiple atomic writes are committed by the writer thread before the reader thread picks them up? 有什么方法可以使用std::atomic_thread_fence来确保在读取器线程将其提取之前,写入器线程已提交了多个原子写入? That is, a guarantee that all writes by the writer thread are committed before a reader thread sees any of them? 就是说,是否保证在读写器线程看到任何写入器之前,已提交写入器线程的所有写入? Or does std::atomic_thread_fence only provide reordering guarantees within a thread? 还是std::atomic_thread_fence仅在线程内提供重排序保证? Currently, just using the .store(std::memory_order_release) for each member doesn't seem to guarantee that all three stores happen before any reads. 当前,仅对每个成员使用.store(std::memory_order_release)似乎并不能保证所有三个存储都在任何读取之前发生。

Obviously, I could use a lock here, but ideally I want to find a way to make this data structure lockfree. 显然,我可以在这里使用锁,但理想情况下,我想找到一种使此数据结构无锁的方法。

I know that I could put highest_x , highest_y , and highest_z in a single struct and allocate two copies of it on the heap, swapping pointers atomically after each write. 我知道我可以将highest_xhighest_yhighest_z放在单个结构中,并在堆中分配它的两个副本,在每次写入后自动交换指针。 Is this the only way to do it? 这是唯一的方法吗?

The devil is here: //updates highest_x, highest_y, highest_z atomically . 魔鬼在这里: //updates highest_x, highest_y, highest_z atomically How do you guarantee that they are, indeed, atomic? 您如何保证它们确实是原子的? Since 3 doubles do not fit into 16B (the largest atomic operation I know on X86_64 platform) the only way to ensure this would be to use mutex . 由于3倍不适合16B(我在X86_64平台上知道的最大原子操作),因此确保这一点的唯一方法是使用mutex

Your problem is not with the fence. 您的问题不在围栏上。 By issuing the fence instruction, you will guarantee that all previous updates would be visible. 通过发布fence说明,您将保证所有以前的更新都是可见的。 What you can't guarantee, though, is that they would not be visible before this. 但是,您不能保证的是之前它们是不可见的。 As a result, you would be able to read the more recent value for one of the vector variables. 结果,您将能够读取矢量变量之一的最新值。

To solve your issue, you should either go with mutex - they are quite efficient when uncontended - or, if you are allergic to mutexes, pointer swap solution you described yourself. 要解决您的问题,您应该使用mutex -它们在无人值守时非常有效-或者,如果您对互斥锁过敏,可以使用您自己描述的指针交换解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM