簡體   English   中英

在這種情況下,'雙重檢查鎖定模式'是否適合std :: mutex?

[英]Is 'double checked locking pattern' good for std::mutex in this situation?

我經常遇到這種線程安全結構的設計。 如下面的version1 ,一個線程很少調用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();

它應該給你滿意的結果,取決於你的矢量有多大。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM