在这种情况下,'double checked locking pattern'对 std::mutex 有好处吗?
Is 'double checked locking pattern' good for std::mutex in this situation?
我经常遇到这种线程安全结构的设计。与以下版本1一样,一个线程可能很少调用foo1::add_data()
,而另一个线程经常调用foo1::get_result()
。出于优化的目的,我认为它可以使用原子来应用双重检查锁定模式 (DCLP),如版本 2 所示。对于这种情况,还有其他更好的设计吗?或者它可以改进,例如使用 std::memory_order
访问原子?
版本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(或非便携式更早)中工作使用原子变量,但你写的结果是未定义的行为。
我认为通过使用
允许许多线程并行读取的"读写锁"可以实现显着的改进(在代码大小以及简单性和性能方面)。Boost 为此提供了shared_mutex
,但从快速浏览来看,这篇博客文章似乎以可移植的方式实现了相同类型的锁,而无需 Boost。
你说你经常打电话给get_average,你有没有考虑过只根据你没有"见过"的数字来计算平均值?它将是 O(n) 而不是 O(n^2)。
它会像
average = (last_average * last_size + static_cast<double>(
std::accumulate(m_vecData.begin() + last_size, m_vecData.end(), 0))) /
m_vecData.size();
它应该给你令人满意的结果,这取决于你的载体有多大。
相关文章:
- 如何在没有死锁和/或争用的情况下正确使用 std::mutex C++?
- std::mutex 如何防止线程修改?
- DRD 报告"conflicting load" std::mutex::lock 上的错误
- std::atomic 和 std::mutex 的相对性能
- 如何解决"'mutex' in namespace 'std' does not name a type"?
- std::lock_guard 怎么可能比 std::mutex::lock() 更快?
- 当"std::lock_guard<std::mutex>"对象没有名称时的不同行为
- std::mutex::lock() 产生奇怪(和不必要的)ASM 代码
- 使用 std::mutex 保护环路
- std::mutex作为一个成员变量对多个线程来说是安全的吗
- std::shared_timed_mutex何时比std::mutex慢,以及何时(不)使用它
- std::mutex 的发布-获取可见性保证是否仅适用于关键部分?
- 死锁使用 std::mutex 来保护多个线程中的 cout
- 返回持有 std::mutex 锁的 RAII 容器类
- 在 C++11 线程中,std::mutex 对内存可见性有什么保证?
- 在任何地方对C++中所有并行线程中的所有锁定和解锁实例使用相同的 std::mutex 和 lock 对象
- 有什么理由C++ 11+ std::mutex 应该声明为全局变量,而不是作为函数参数传递到 std::thread 中
- 将 std::atomic<bool> 与 std::mutex 结合使用的正确性
- Inline STD :: MUTEX在标题文件中
- Using std::mutex, std::condition_variable and std::unique_lo