Java的循环屏障的C++版本是什么?

3
在Java中,多个线程可以在某个点等待所有其他线程,以便它们在所有其他线程完成第一个块之前不开始新的代码块:
CyclicBarrier barrier = new CyclicBarrier(2);

// thread 1
readA();
writeB();
barrier.await();
readB();
writeA();

// thread 2
readA();
writeB();
barrier.await();
readB();
writeA();

是否有精确或简单的转换方法转换到C ++?

另外,在OpenCL中,有一个类似的指令:

readA();
writeB();
barrier(CLK_GLOBAL_MEM_FENCE);
readB();
writeA();

因此,所有相邻的线程都会等待彼此,但这只是一个受限制的C实现。


1
将Java和C++这两种不相关的语言进行比较,可能会事与愿违。事实上,在使用C++时,你应该忘掉在Java中学到的一切,从零开始,并逐步提高。 - Ron
@Ron 你的意思是像有一个单独的线程来监视原子计数器,并在计数器达到N时从该线程通知所有线程吗?那么C++中就没有简单的命令。 - huseyin tugrul buyukisik
2
C++标准库中不存在这样的东西。您可以从可用的同步原语实现它(看起来互斥量、计数器和条件变量会起到作用),或者寻找现有的第三方实现。 - Igor Tandetnik
1
锁定互斥量的开销将远远超过任何计数器操作数个数量级。 - Igor Tandetnik
@Brandon 谢谢。条件等待看起来更简单。 - huseyin tugrul buyukisik
显示剩余5条评论
3个回答

3

C++ STL没有循环屏障。你可以向标准委员会提出建议 :)

像Oracle或Microsoft这样的公司可以快速决定将什么添加到他们的语言库中。对于C++,人们必须达成一致意见,这可能需要一段时间。

256个线程是很多的。对于所有与性能相关的问题,您需要测量代码以做出明智的决策。对于256个线程,我会倾向于使用10个由第11个屏障同步的屏障。您需要进行测量以了解是否确实更好。

查看我的C++循环屏障实现,受Java启发。我写了它几年前。它基于我在http://studenti.ing.unipi.it/~s470694/a-cyclic-thread-barrier/(链接不再有效...)找到的其他人(有缺陷的)代码。代码非常简单(无需归功于我)。当然,它是“按原样提供”的,没有任何保证。

// Modeled after the java cyclic barrier.
// Allows n threads to synchronize.
// Call Break() and join your threads before this object goes out of scope
#pragma once

#include <mutex>
#include <condition_variable>


class CyclicBarrier
{
public:
    explicit CyclicBarrier(unsigned numThreads)
        : m_numThreads(numThreads)
        , m_counts{ 0, 0 }
        , m_index(0)
        , m_disabled(false)
    { }

    CyclicBarrier(const CyclicBarrier&) = delete;
    CyclicBarrier(CyclicBarrier &&) = delete;
    CyclicBarrier & operator=(const CyclicBarrier&) = delete;
    CyclicBarrier & operator=(CyclicBarrier &&) = delete;

    // sync point
    void Await()
    {
        std::unique_lock<std::mutex> lock(m_requestsLock);
        if (m_disabled)
            return;

        unsigned currentIndex = m_index;
        ++m_counts[currentIndex];

        // "spurious wakeup" means this thread could wake up even if no one called m_condition.notify!
        if (m_counts[currentIndex] < m_numThreads)
        {
            while (m_counts[currentIndex] < m_numThreads)
                m_condition.wait(lock);
        }
        else
        {
            m_index ^= 1; // flip index
            m_counts[m_index] = 0;
            m_condition.notify_all();
        }
    }

    // Call this to free current sleeping threads and prevent any further awaits.
    // After calling this, the object is no longer usable.
    void Break()
    {
        std::unique_lock<std::mutex> lock(m_requestsLock);
        m_disabled = true;
        m_counts[0] = m_numThreads;
        m_counts[1] = m_numThreads;
        m_condition.notify_all();
    }

private:
    std::mutex     m_requestsLock;
    std::condition_variable m_condition;
    const unsigned m_numThreads;
    unsigned       m_counts[2];
    unsigned       m_index;
    bool           m_disabled;
};

2
  • C++20 has std::barrier now.

  • POSIX has "pthread_barrier_t" with the following interface:

     int pthread_barrier_init(pthread_barrier_t *restrict barrier, 
           const pthread_barrierattr_t *restrict attr, unsigned count); 
    
     int pthread_barrier_wait(pthread_barrier_t *barrier);
     int pthread_barrier_destroy(pthread_barrier_t *barrier);
    

1

你可以在boost库中找到它,它被称为barrier,但缺少等待超时选项。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接