簡體   English   中英

使用原子變量,CyclicBarrier中的C ++倒計時出錯[請提供無鎖的解決方案]

[英]C++ countdown in CyclicBarrier going wrong using atomic variables [solutions without locks please]

我正在嘗試從頭開始在C ++中實現循環屏障。 目的是實現與Java實現盡可能一致的方法。 類參考在這里。 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html

現在,在我的測試中,returnStatus應該針對成功觸發屏障的每個線程,其值范圍為barrierLimit-1到零。 我正在嘗試使用原子變量和內存圍欄來實現這一目標。 但是我的代碼無法通過測試,在某些情況下,兩個線程的returnStatus值相同。

請問有人建議是否有任何技術可以幫助解決這一問題。 我想解決此問題而不使用鎖,以便我可以盡可能地真正應用無鎖行為。

完整的代碼參考位於: https : //github.com/anandkulkarnisg/CyclicBarrier/blob/master/CyclicBarrier.cpp

Sample test case result is below [ buggy case ]:

I am currently in thread id = 140578053969664.My barrier state count is = 4
I am currently in thread id = 140577877722880.My barrier state count is = 2
I am currently in thread id = 140577550407424.My barrier state count is = 1
I am currently in thread id = 140577936471808.My barrier state count is = 2
I am currently in thread id = 140577760225024.My barrier state count is = 0


The code snippet is below.

        // First check and ensure that the barrier is in good / broken state.
        if(!m_barrierState && !m_tripStatus)
        {
            // First check the status of the variable and immediately exit throwing exception if the count is zero.
            int returnResult;
            if(m_count == 0)
                throw std::string("The barrier has already tripped. Pleas reset the barrier before use again!!" + std::to_string(returnResult));

            // First ensure that the current wait gets the waiting result assigned immediately.

            std::atomic_thread_fence(std::memory_order_acquire);
            m_count.fetch_sub(1, std::memory_order_seq_cst);
            returnResult = m_count.load();
    std::atomic_thread_fence(std::memory_order_release);
std::atomic_thread_fence(std::memory_order_acquire);
m_count.fetch_sub(1, std::memory_order_seq_cst);      // [1]
returnResult = m_count.load();                        // [2]
std::atomic_thread_fence(std::memory_order_release);

[2]多個線程同時執行此步驟。 std::atomic_thread_fence不會阻止其他線程同時運行相同的代碼。 這就是2個線程最終得到相同值的方式。

而是在標記為[1]的行上捕獲fetch_sub的返回值。

returnResult = m_count.fetch_sub(1, std::memory_order_seq_cst) - 1;

順便說一句,我敢肯定你在這里不需要柵欄。 (我真的不能不看更多功能就知道。)如果這樣做,您可能只是將returnResult切換為原子。

似乎您正在使用隔離柵,就好像它們是事務性內存一樣。 他們不是。 該發行版實質上控制了由使用獲取的任何CPU感知到的存儲順序保證。 只要不違反順序保證,就可以在實際處理發行版之前自由傳播寫入。 作為一個思想實驗,設想執行[1] ,然后發生上下文切換,經過一百萬年,然后執行[2] 現在假設m_count與一百萬年前具有相同的值顯然是荒謬的。 該發行版可能會刷新寫緩沖區,但是可能已經清空了更改。

最后,如果將seq_cstacquire / release語義混合seq_cst ,可能會發生奇怪的事情。 抱歉,這很含糊,但我對它的理解不夠充分,無法解釋。

暫無
暫無

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

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