【发布时间】:2011-12-28 20:19:51
【问题描述】:
我有一些具有以下结构的多线程 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();
检查点 B 之后的工作是在所有线程仅到达检查点 A 时开始的工作,因此我提出了“软屏障”的概念。
通常,多线程库仅提供“硬屏障”,其中所有线程必须达到某个点才能继续。显然可以在检查点 B 使用硬屏障。
使用软屏障可以缩短执行时间,特别是因为检查点 A 和 B 之间的工作可能没有在线程之间进行负载平衡(即 1 个到达检查点 A 但未到达检查点 B 的慢线程可能导致所有其他人在检查站 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 之间的工作自动在线程之间进行负载平衡(这有时相当困难)。
感谢您的任何建议/见解:)
【问题讨论】:
-
我对你的问题感到困惑。如果你在 A 处有一个硬屏障,那么 A 之后的任何代码,包括 B 之后的代码,都只会在每个线程通过该屏障之后执行。你在 B 需要什么障碍?
-
@Walter 在 A 处使用硬屏障在功能上是正确的,但可能会失去性能。考虑在允许任何线程开始 A 和 B 之间的工作之前等待一个慢线程到达 A 的惩罚(因为基于结构我们真的不需要在 A 等待)。
标签: c++ multithreading openmp