在 C++ 中,互斥锁保护数据的副本是否会被优化掉?
我想制作受保护数据的快照,并在互斥锁之外读取它。不过,这个副本是否会得到优化,让我要么读取互斥体内部的原始受保护数据(对性能不利),或更糟糕,读取互斥体外部的原始受保护数据(不安全)?
话题1
while (1)
{
my_mutex.lock();
data = ... /* Modifications to the data. */
my_mutex.unlock();
... /* Unrelated stuff. */
}
话题2
while (1)
{
my_mutex.lock();
snapshot = data; /* Take a snapshot of the protected data. */
my_mutex.unlock();
... /* Read various things in the snapshot. */
}
互斥锁上的锁定和解锁操作充当内存屏障。在锁定之前或解锁之后,任何对象的读取或写入都不能重新排序。所以代码是安全的。
(一个例外是具有本地作用域的对象,其地址尚未传递到函数外部,因此没有其他线程可能同时访问它。)
从技术上讲,副本可以被优化,例如,如果您从未读取存储到
snapshot
中的值。编译器无法将 data
的读取移到临界区之外,但如果可以证明没有必要,它可以完全跳过读取。
还允许编译器从临界区内的
data
进行多次读取;这不会引入数据竞争,除非已经存在数据竞争。也许这对性能不利,但它是一致的; C++ 标准通常不强制要求性能。如果您的编译器生成次优代码,您必须直接处理它们。