繁体   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