Barrier class 分而治之(忙时销毁互斥体)C++

Barrier class with divide and conquer (mutex destroyed while busy) C++

我已经尝试实施障碍 class。我想使用分而治之算法对此进行测试。我的class定义如下:

class barrier{
private:
    mutex mtx;
    condition_variable cv;
    atomic<int> counter;
    atomic<int> waiting;
    atomic<int> thread_count;

public:
    barrier(int count) : thread_count(count), counter(0), waiting(0) {}

    void wait()
    {
        //fence mechanism
        unique_lock<mutex> lock(mtx);
        ++counter;
        ++waiting;
        cv.wait(lock, [&] {return counter >= thread_count; });
        --waiting;
        if (waiting == 0) counter = 0;
        for (int i = 0; i < thread_count; ++i) cv.notify_one();
        lock.unlock();
    }
};

关于分治算法,我是这样实现的:

int main() {
    vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
    int n = size(v)/2;

    while (n >= 1) {
        dnc_light(v, n);
        n /= 2;
    }

    return 0;
}

void dnc_light (vector<int> &v, int n) {
    thread trd[50];
    barrier bar(n);

    for (int i = 0; i < n; ++i) {
        trd[i] = thread([&] {
            v[i] += v[i + n];
            bar.wait();
        });
    }
}

然而,这会导致 "mutex destroyed while busy" - 错误。怎么来的?我需要动态处理 barrier bar(...) 的大小。

This however results in a "mutex destroyed while busy" - error. How come?

dnc_light 使用对本地 barrier 对象的引用创建多个线程。然后函数 returns 破坏了那个局部 barrier 那些线程仍在使用,这导致 "mutex destroyed while busy" 错误。

此外,线程是可连接的,因此它们的析构函数将抛出异常,因为它们既没有连接也没有分离。

解决方法是在从函数返回之前加入线程:

void dnc_light(vector<int> &v, int n) {
    vector<thread> trd(n);
    barrier bar(n);

    for (int i = 0; i < n; ++i) {
        trd[i] = thread([&](){
            v[i] += v[i + n];
            bar.wait();
        });
    }

    for(auto& t : trd)
        t.join();
}

在上面的代码中,你根本不需要屏障,因为这个连接循环一直等到所有线程终止。


barrier 中的变量不需要是原子的,因为它只在持有互斥锁时访问它们。简化:

class barrier {
    mutex mtx;
    condition_variable cv;
    int const thread_count;
    int counter{0};
    int waiting{0};

public:
    barrier(int count) : thread_count(count) {}

    void wait() {
        unique_lock<mutex> lock(mtx);
        ++counter;
        ++waiting;
        cv.wait(lock, [&](){
            return counter >= thread_count;
        });
        if(waiting == thread_count)
            cv.notify_all();
        if(!--waiting)
            counter = 0;
    }
};