c++ - 如何在多线程 C++ 中实现 "soft barrier"

标签 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 之间的工作可能无法在线程之间进行负载平衡(即 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 之间的工作自动在线程之间进行负载平衡(这有时相当困难).

感谢任何建议/见解:)

最佳答案

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

int counter = 0;
condition_variable cond;

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

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

在所有线程到达检查点A之前,任何线程都不能通过检查点B。

关于c++ - 如何在多线程 C++ 中实现 "soft barrier",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8125330/

相关文章:

c++ - 在c++中,虚函数、函数覆盖和多态性是否相互关联?

java - Android 中的套接字连接错误

c++ - Makefile 与 OpenMP : cannot specify -o with -c, -S 或 -E 与多个文件

c++ - 如何在 OpenMP C++ 中分配动态内存

c++ - 如何在函数调用(不是作为工具提示而是实际编写)或声明中显示函数参数名称

c++ - 如何从 QTabWidget 获取小部件?

c++ - MS VC++ 编译器模棱两可

c++ - 在一个线程中创建对象并使用 std::atomic 访问另一个线程

c++ - 在 C++ 中使用带有共享变量的 pthread 进行多线程

c++ - 简单的基于任务的 OpenMP 应用程序挂起