如何实施";“软屏障”;在多线程c++; 我有一些多线程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();

如何实施";“软屏障”;在多线程c++; 我有一些多线程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();,c++,multithreading,openmp,C++,Multithreading,Openmp,检查点B之后的工作可能是在所有线程只到达检查点A的情况下开始的,因此我提出了“软屏障”的概念 通常,多线程库只提供“硬屏障”,其中所有线程必须达到某个点才能继续。显然,在检查点B可以使用硬屏障 使用软屏障可以带来更好的执行时间,特别是因为检查点a和B之间的工作可能不会在线程之间实现负载平衡(即,1个到达检查点a但未到达B的慢线程可能会导致所有其他线程在检查点B之前在屏障处等待) 我曾尝试使用原子学来同步事情,我100%肯定地知道它不一定能工作。例如,使用openmp语法,在并行部分开始之前: s

检查点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(使用轮询):

我设计了一些实验,在实验中,我用一个原子来指示某些操作在完成之前。这个实验在大多数情况下使用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。

哪些库支持条件变量?这是否保证没有像我给出的原子解决方案那样的可能的竞争条件?@Jason
boost::thread
std::thread在C++11
中,可能还有
tbb
。这是我刚写的一段粗略的代码。希望它能帮助你。谢谢你提出条件变量,但是经过一点研究,我认为它不能保证没有可能的比赛条件。据我所知,避免竞速的唯一方法是,由于缓存未命中(例如外部内存访问)而导致的最坏情况延迟仍然比线程之间的同步机制(例如锁或您建议的条件变量)快。显然,这将取决于所述同步结构的实现、硬件支持和许多其他参数。(续…)讽刺的是,这个软屏障的全部目的是加速计算,但为了保证正确性,必须使用缓慢的同步结构。我认为真正的解决方案是重新构造代码,使其具有更好的负载平衡特性。无论如何,再次感谢:)我对你的问题感到困惑。如果您在a处有一个硬屏障,那么a之后的任何代码,包括B之后的代码,都将仅在每个线程都通过该屏障后执行。“你为什么需要在B处设置障碍物?”沃尔特在a处使用硬障碍物在功能上是正确的,但可能会失去性能。考虑在一个慢线程等待A之前的惩罚,然后允许任何线程在A和B之间的工作开始(因为基于结构,我们真的不需要在A上等待)。
int counter = 0;
condition_variable cond;

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

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