如何在多线程c ++中实现“软屏障”

时间:2011-11-14 17:12:39

标签: c++ multithreading openmp

我有一些具有以下结构的多线程c ++代码:

do_thread_specific_work();
update_shared_variables();
//checkpoint A
do_thread_specific_work_not_modifying_shared_variables();
//checkpoint B
do_thread_specific_work_requiring_all_threads_have_updated_shared_variables();

如果所有线程都只到达了检查点A,那么检查点B之后的工作可能已经开始,因此我的概念是“软屏障”。

通常,多线程库只提供“硬障碍”,其中所有线程必须在任何可以继续之前到达某个点。显然,在检查站B可以使用硬屏障。

使用软屏障可以带来更好的执行时间,尤其是因为检查点A和B之间的工作可能无法在线程之间进行负载平衡(即,已到达检查点A而非B的1个慢线程可能导致所有其他人在检查站B)之前等待屏障。

我尝试过使用原子来同步事物,我知道100%确定无法保证工作。例如,使用openmp语法,在并行部分开始之前:

shared_thread_counter = num_threads;  //known at compile time
#pragma omp flush

然后在检查站A:

#pragma omp atomic
shared_thread_counter--;

然后在检查站B(使用民意调查):

#pragma omp flush
while (shared_thread_counter > 0) {
  usleep(1);  //can be removed, but better to limit memory bandwidth
  #pragma omp flush
}

我设计了一些实验,其中我使用原子来指示在完成之前的某些操作。这个实验大部分时间都可以使用2个线程,但是当我有很多线程(比如20或30)时,它会一直失败。我怀疑这是因为现代CPU的缓存结构。即使一个线程在执行原子减量之前更新了某个其他值,也不能保证按该顺序由另一个线程读取。考虑另一个值是缓存未命中且原子减量是缓存命中的情况。

回到我的问题,如何正确实施这个“软屏障”?是否有任何内置功能可以保证这种功能?我更喜欢openmp,但我熟悉其他大多数常见的多线程库。

现在作为一种解决方法,我在检查点B使用了一个硬屏障,我重新组织了我的代码,使检查点A和B之间的工作自动在线程之间进行负载平衡(有时候这很困难) )。

感谢您的任何建议/见解:)

1 个答案:

答案 0 :(得分:2)

如何使用条件变量?我不确定是否提供了条件变量,因为我不熟悉OpenMP。

int counter = 0;
condition_variable cond;

// checkpoint A
++counter;
cond.notify_all();

// checkpoint B
cond.wait_until( counter >= NUM_THREADS );

在每个线程到达检查点A之前,没有线程可以通过检查点B.