我经常遇到这种线程安全结构的设计。如下面的version1,一个线程可能很少调用foo1::add_data()
,而另一个线程经常调用foo1::get_result()
。出于优化的目的,我认为它可以使用原子来应用双重检查锁定模式 (DCLP),如 version2 所示。这种情况还有其他更好的设计吗?还是可以对其进行改进,例如使用 std::memory_order
访问 atomic?
版本 1:
class data {};
class some_data {};
class some_result {};
class foo1
{
public:
foo1() : m_bNeedUpdate(false) {}
void add_data(data n)
{
std::lock_guard<std::mutex> lock(m_mut);
// ... restore new data to m_SomeData
m_bNeedUpdate = true;
}
some_result get_result() const
{
{
std::lock_guard<std::mutex> lock(m_mut);
if (m_bNeedUpdate)
{
// ... process mSomeData and update m_SomeResult
m_bNeedUpdate = false;
}
}
return m_SomeResult;
}
private:
mutable std::mutex m_mut;
mutable bool m_bNeedUpdate;
some_data m_SomeData;
mutable some_result m_SomeResult;
};
版本 2:
class foo2
{
public:
foo2() : m_bNeedUpdate(false) {}
void add_data(data n)
{
std::lock_guard<std::mutex> lock(m_mut);
// ... restore new data to m_SomeData
m_bNeedUpdate.store(true);
}
some_result get_result() const
{
if (m_bNeedUpdate.load())
{
std::lock_guard<std::mutex> lock(m_mut);
if (m_bNeedUpdate.load())
{
// ... process mSomeData and update m_SomeResult
m_bNeedUpdate.store(false);
}
}
return m_SomeResult;
}
private:
mutable std::mutex m_mut;
mutable std::atomic<bool> m_bNeedUpdate;
some_data m_SomeData;
mutable some_result m_SomeResult;
};
最佳答案
问题是版本 2 不是线程安全的,至少 根据 C++11(和更早的 Posix);你正在访问 可以在没有访问权限的情况下修改的变量 保护。 (众所周知,双重检查锁定模式是 坏了,看 http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf .) 它可以通过以下方式在 C++11(或不可移植的更早版本)中工作 使用原子变量,但你所写的结果 未定义的行为。
关于c++ - 在这种情况下 'double checked locking pattern' 对 std::mutex 有用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22804739/