在编写多线程代码时,我经常需要读/写共享内存。为防止数据竞争,首选解决方案是使用 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 相比,使用这些同步值是否有任何缺点/性能开销?
答案 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)
如果您深入了解每种情况下实际发生的情况,您只会发现说和做同一件事的不同方式。