用于单向数据传输的C ++中的双重检查锁定是否安全?

时间:2016-11-25 04:01:06

标签: c++ multithreading performance c++11 double-checked-locking

我继承了一个我尝试提高性能的应用程序,它目前使用互斥锁(std::lock_guard<std::mutex>)将数据从一个线程传输到另一个线程。一个线程是低频(慢速)线程,它只是修改另一个线程要使用的数据。

另一个线程(我们将快速调用)具有相当严格的性能要求(它需要每秒执行最大周期数)并且我们认为这会受到使用互斥锁的影响。

基本上,目前的逻辑是:

slow thread:             fast thread:
    occasionally:            very-often:
        claim mutex              claim mutex
        change data              use data
        release mutex            release mutex

为了让快速线程以最大吞吐量运行,我想尝试删除必须执行的互斥锁数量。

怀疑双锁定检查模式的变体可能在这里有用。我知道它在双向数据流(或单例创建)方面存在严重问题,但在我的情况下,责任区域在哪个线程执行共享数据的哪些操作(以及何时)方面稍微有点限制。

基本上,慢速线程设置数据并且永远不会再次读取或写入数据,除非有新的更改。快速线程使用和更改数据但从不希望将任何信息传递回另一个线程。换句话说,所有权主要是以一种方式流动。

我想知道是否有人可以在我想到的策略中挑选任何漏洞。

新想法是拥有两个数据集,一个是当前的,一个是挂起的。在我的情况下不需要队列,因为传入的数据会覆盖以前的数据。

挂起的数据只能由互斥锁控制下的慢速线程写入,它将有一个原子标志,表示它已经写入并放弃了控制(暂时)。

快速线程将继续使用当前数据(没有互斥锁),直到设置原子标志为止。由于它负责将待处理转移到当前,因此可以确保当前数据始终保持一致。

在设置标志的位置,它将锁定互斥锁,并将挂起转移到当前,清除标记,解锁互斥锁并继续。

所以,基本上,快速线程全速运行,只有当知道需要传输待处理数据时才会锁定互斥锁。

进入更具体的细节,该课程将拥有以下数据成员:

std::atomic_bool m_newDataReady;
std::mutex       m_protectData;
MyStruct         m_pendingData;
MyStruct         m_currentData;

在慢速线程中接收新数据的方法是:

void NewData(const MyStruct &newData) {
    std::lock_guard<std::mutex> guard(m_protectData);
    m_newDataReady = false;
    Transfer(m_newData, 'to', m_pendingData);
    m_newDataReady = true;
}

清除标志会阻止快速线程甚至尝试检查新数据,直到立即传输操作完成。

快速线程有点棘手,使用标志将互斥锁保持在最低限度:

while (true) {
    if (m_newDataReady) {
        std::lock_guard<std::mutex> guard(m_protectData);
        if (m_newDataReady) {
            Transfer(m_pendingData, 'to', m_currentData);
            m_newDataReady = false;
        }
    }

    Use (m_currentData);
}

现在在我看来,在快速线程中使用此方法可以提高性能:

  • 只有一个地方在互斥锁的控制范围之外使用原子标志,并且它是一个原子意味着它的状态应该在那里保持一致。
  • 即使它一致,互斥锁区域内的第二次检查也应该提供一个安全阀(当我们知道它一致)。
  • 数据传输仅在互斥锁的控制下执行永远,因此应始终保持一致。
  • 快速线程中的外部循环意味着将避免不必要的互斥锁 - 它们只有在标志为真时才会完成(或者#34;半真&#34;,可能是不一致的状态)
  • 内在的if会照顾到这个&#34; half-true&#34;在检查和锁定互斥锁之间,标志已被清除的可能性。

我无法看到这个策略中的任何漏洞但是,鉴于我只是在标准C ++世界中进入原子/线程,它可能是我&#39我错过了什么。

使用此方法有任何明显问题吗?

0 个答案:

没有答案