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

时间:2017-01-04 20:31:10

标签: c++ multithreading c++11 atomic lock-free

假设我在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;
}

我将拥有 R 读者线程和一个编写器线程。作者线程将更新零个或多个highest_*成员。如果读者线程调用get_highs()我需要写入线程的push_vec()函数的当前调用的所有写入对读者线程可读之前读者线程读取{{ 1}},highest_x等生成一个向量。

现在,我知道如果highest_y足够小,我可以使用Vec。问题是,如果它太大,则无法使用这些存储/加载的本机CPU指令。有没有办法使用std::atomic<Vec>来保证编写器线程在读取器线程选择之前提交多个原子写入?也就是说,保证编写器线程的所有写入都是在读者线程看到它们之前提交的?或std::atomic_thread_fence仅提供线程内的重新排序保证?目前,仅为每个成员使用std::atomic_thread_fence似乎并不能保证所有三个商店都在任何读取之前发生。

显然,我可以在这里使用锁,但理想情况下我想找到一种方法使这个数据结构无锁。

我知道我可以将.store(std::memory_order_release)highest_xhighest_y放在一个结构中,并在堆上分配它的两个副本,在每次写入后以原子方式交换指针。这是唯一的方法吗?

1 个答案:

答案 0 :(得分:4)

魔鬼在这里://updates highest_x, highest_y, highest_z atomically。你如何保证它们确实是原子的?由于3个双精度不适合16B(我在X86_64平台上知道的最大原子操作),确保这一点的唯一方法是使用mutex

你的问题不在围栏上。通过发出fence指令,您将保证所有先前的更新都是可见的。但是,你不能保证的是,之前不会显示它们。因此,您将能够读取其中一个矢量变量的更新值。

要解决您的问题,您应该选择mutex - 它们在无条件时非常有效 - 或者,如果您对互斥体过敏,那么您自己就会描述指针交换解决方案。