C++ C++;Fork-Join并行阻塞
假设您希望并行运行一个部分,然后合并回主线程,然后并行返回到该部分,依此类推。类似于童年游戏的红灯绿灯 我已经给出了一个我正在尝试做的例子,我使用一个条件变量在开始时阻止线程,但是希望并行地启动它们,但是在结束时阻止它们,这样它们就可以串行地打印出来。*=操作可能是一个跨越数秒的更大操作。重用线程也很重要。使用任务队列可能太重 我需要使用某种阻塞结构,它不仅仅是一个普通的忙循环,因为我知道如何用忙循环解决这个问题 英文:C++ C++;Fork-Join并行阻塞,c++,multithreading,parallel-processing,C++,Multithreading,Parallel Processing,假设您希望并行运行一个部分,然后合并回主线程,然后并行返回到该部分,依此类推。类似于童年游戏的红灯绿灯 我已经给出了一个我正在尝试做的例子,我使用一个条件变量在开始时阻止线程,但是希望并行地启动它们,但是在结束时阻止它们,这样它们就可以串行地打印出来。*=操作可能是一个跨越数秒的更大操作。重用线程也很重要。使用任务队列可能太重 我需要使用某种阻塞结构,它不仅仅是一个普通的忙循环,因为我知道如何用忙循环解决这个问题 英文: 线程1创建10个被阻塞的线程 线程1向所有线程发出启动信号(互不阻塞) 线
//条件变量示例
#include//std::cout
#include//std::thread
#包括//std::mutex、std::unique\u lock
#include//std::condition\u变量
#包括
std::互斥mtx;
std::条件变量cv;
bool ready=false;
std::原子计数(0);
bool end=false;
INTA[10];
void doublea(整数id){
当(!结束){
标准:唯一锁定lck(mtx);
而(!ready)cv.wait(lck);
a[id]*=2;
计数。取加(1);
}
}
void go(){
标准:唯一锁定lck(mtx);
就绪=正确;
cv.通知所有人();
ready=false;//天真
而(count.load()<10)睡眠(1);
对于(int i=0;i<10;i++){
std::cout您可以使用barrier或condition变量启动所有线程。然后线程可以等待所有线程结束其工作(通过所有线程上的join方法,它是阻塞的)然后在一个循环中打印他们的数据。有效地实现它并不是那么简单。此外,除非您正在学习这个主题,否则它没有任何意义。条件变量在这里不是一个好的选择,因为它不能很好地伸缩
我建议你看看成熟的运行时库是如何实现fork-join并行的,并从中学习或在你的应用程序中使用它们
OpenMP是与您所寻找的最接近的模型,并且它具有最有效的fork-join屏障实现。尽管如此,它也有其缺点,因为它是为HPC设计的,并且缺乏动态可组合性。TBB和Cilk最适合嵌套并行性以及可在外部pa环境中使用的模块和库中的使用所有区域。为什么count
是原子的?为什么一边使用条件变量,另一边使用忙睡眠?@UmNyobe我明确不想使用忙睡眠。线程应该在等待通知时睡眠。对于你的另一个问题,count是原子的,因为幸运的话,它可以一次增加多个线程。IncrMENT是一个两阶段的过程。这不是一个解决方案,因为线程连接后需要重新创建。你说我正在尝试学习是正确的。我以前看过TBB和OpenMP,但OpenMP大量使用pragmas令人不快,TBB有很多锅炉板来做简单的事情。不过我很乐意再给他们一个l阅读并使用它们。为了真正阅读我的问题,我会给你答案。你不想在下面混合前端(使用模型)和运行库。你可以为这些运行时中的任何一个编写自己的前端。
// condition_variable example
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
#include <atomic>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
std::atomic<int> count(0);
bool end = false;
int a[10];
void doublea (int id) {
while(!end) {
std::unique_lock<std::mutex> lck(mtx);
while (!ready) cv.wait(lck);
a[id] *= 2;
count.fetch_add(1);
}
}
void go() {
std::unique_lock<std::mutex> lck(mtx);
ready = true;
cv.notify_all();
ready = false; // Naive
while (count.load() < 10) sleep(1);
for(int i = 0; i < 10; i++) {
std::cout << a[i] << std::endl;
}
ready = true;
cv.notify_all();
ready = false;
while (count.load() < 10) sleep(1);
for(int i = 0; i < 10; i++) {
std::cout << a[i] << std::endl;
}
end = true;
cv.notify_all();
}
int main () {
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i) {
a[i] = 0;
threads[i] = std::thread(doublea,i);
}
std::cout << "10 threads ready to race...\n";
go(); // go!
return 0;
}