具有分而治之的障碍类(在繁忙时被破坏的互斥体)C ++

时间:2017-11-09 09:36:31

标签: multithreading c++11 barrier

我尝试过实施障碍课程。我想用分而治之的算法来测试它。我的课程定义如下:

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();
        });
    }
}
然而,这会导致在忙碌时摧毁&#34;互斥体。 - 错误。怎么会?我需要动态处理barrier bar(...)的大小。

1 个答案:

答案 0 :(得分:2)

  然而,这会导致在忙碌时摧毁&#34;互斥体。 - 错误。怎么样?

dnc_light创建多个线程,引用本地barrier对象。然后该函数返回销毁那些线程仍然使用的本地barrier,这会导致&#34;互斥体在忙碌时被销毁#34;错误。

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

修复是在从函数返回之前加入线程:

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;
    }
};