我尝试过实施障碍课程。我想用分而治之的算法来测试它。我的课程定义如下:
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(...)
的大小。
答案 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;
}
};