在C++ 11中实现boost :: barrier

h4l*_*c0n 16 multithreading barrier c++11

我一直试图让一个项目摆脱每个boost参考并切换到纯C++ 11.

有一次,创建了线程工作者,它等待一个障碍来给出'go'命令,完成工作(通过N个线程传播)并在所有这些完成时同步.基本思想是主循环给出了go命令(boost :: barrier .wait())并等待具有相同函数的结果.

我在一个不同的项目中实现了一个基于Boost版本的定制Barrier,一切都运行得很好.实施如下:

Barrier.h:

class Barrier {
public:
    Barrier(unsigned int n);
    void Wait(void);
private:
    std::mutex counterMutex;
    std::mutex waitMutex;

    unsigned int expectedN;
    unsigned int currentN;
};
Run Code Online (Sandbox Code Playgroud)

Barrier.cpp

Barrier::Barrier(unsigned int n) {
    expectedN = n;
    currentN = expectedN;
}

void Barrier::Wait(void) {
    counterMutex.lock();

    // If we're the first thread, we want an extra lock at our disposal

    if (currentN == expectedN) {
        waitMutex.lock();
    }

    // Decrease thread counter

    --currentN;

    if (currentN == 0) {
        currentN = expectedN;
        waitMutex.unlock();

        currentN = expectedN;
        counterMutex.unlock();
    } else {
        counterMutex.unlock();

        waitMutex.lock();
        waitMutex.unlock();
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码已在iOS和Android的NDK上使用,没有任何问题,但在Visual Studio 2013项目上尝试时,似乎只有锁定互斥锁的线程才能解锁它(断言:解锁无主互斥锁).

是否有任何非旋转(阻塞,例如这个)版本的屏障,我可以使用适用于C++ 11?我只能找到使用忙碌等待的障碍,这是我想要阻止的(除非真的没有理由).

小智 26

class Barrier {
public:
    explicit Barrier(std::size_t iCount) : 
      mThreshold(iCount), 
      mCount(iCount), 
      mGeneration(0) {
    }

    void Wait() {
        std::unique_lock<std::mutex> lLock{mMutex};
        auto lGen = mGeneration;
        if (!--mCount) {
            mGeneration++;
            mCount = mThreshold;
            mCond.notify_all();
        } else {
            mCond.wait(lLock, [this, lGen] { return lGen != mGeneration; });
        }
    }

private:
    std::mutex mMutex;
    std::condition_variable mCond;
    std::size_t mThreshold;
    std::size_t mCount;
    std::size_t mGeneration;
};
Run Code Online (Sandbox Code Playgroud)

  • 此实现是可重用的,并且可以防止虚假唤醒。 (2认同)
  • @jamshid 不,这不是一个拼写错误,请查看 [`列表初始化`](https://en.cppreference.com/w/cpp/language/list_initialization) 上的示例 (2认同)

nos*_*sid 17

使用std :: condition_variable而不是std :: mutex来阻塞所有线程,直到最后一个线程到达屏障.

class Barrier
{
private:
    std::mutex _mutex;
    std::condition_variable _cv;
    std::size_t _count;
public:
    explicit Barrier(std::size_t count) : _count(count) { }
    void Wait()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        if (--_count == 0) {
            _cv.notify_all();
        } else {
            _cv.wait(lock, [this] { return _count == 0; });
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

  • 请注意,此实现仅适用于一次性使用屏障,但可防止虚假唤醒. (6认同)

归档时间:

查看次数:

9702 次

最近记录:

6 年,11 月 前