多线程 - 同步值与互斥锁?

时间:2021-03-06 14:00:41

标签: c++ multithreading concurrency shared-memory

在编写多线程代码时,我经常需要读/写共享内存。为防止数据竞争,首选解决方案是使用 lock_guard 之类的内容。然而最近,我遇到了“同步值”的概念,它通常在以下几行中实现:

template <typename T>
class SynchronizedValue {
    T value;
    std::mutex lock;
    /* Public helper functions to read/write to a value, making sure the lock is locked when the value is written to*/
};

此类同步值将有一个方法 SetValueTo,它将锁定互斥锁、写入值并解锁互斥锁,确保您可以安全地写入值而不会出现任何数据竞争。

这使得编写多线程代码变得更加容易!但是,与互斥锁/lock_guard 相比,使用这些同步值是否有任何缺点/性能开销?

2 个答案:

答案 0 :(得分:2)

<块引用>

使用这些 SynchronisedValues... 有什么缺点/性能开销吗?

在问有没有缺点之前,先问问有没有好处。标准 C++ 库已经定义了 std::atomic<T>。你没有说出你的想法 /* public helper functions...*/,但如果他们只是 value 的 getter 和 setter,那么你的 SynchronizedValues<T> 课程提供了什么你还没有得到的来自std::atomic<T>


为什么“原子”变量不能消除对互斥体的需求,B.T.W.互斥体不仅仅是确保内存更新的“可见性”:考虑互斥体的最重要方式是它们可以保护程序中数据之间的关系

例如,假设一个程序有多个容器用于某类对象,假设该程序需要将对象从一个容器移动到另一个容器,并假设某个线程偶尔统计所有 的对象,并保证得到准确的计数。

程序可以使用互斥锁来实现这一点。它只需要遵守两个简单的规则; (1) 没有线程可以从任何容器中删除一个对象,除非它锁定了互斥锁,并且 (2) 没有线程可以释放互斥锁,直到每个对象都在容器中。如果所有线程都遵守这两条规则,那么如果在开始计数之前锁定互斥锁,则可以保证对对象进行计数的线程找到所有对象。

问题是,你不能保证仅仅通过使所有变量atomic,因为atomic不保护相关变量之间的任何关系和任何other 变量。它最多只保护一些“原子”操作(例如原子增量)前后变量值之间的关系。

当有多个变量参与关系时,您必须有一个互斥锁(或与互斥锁等效的东西)。

答案 1 :(得分:1)

如果您深入了解每种情况下实际发生的情况,您只会发现说和做同一件事的不同方式。