Multithreading OpenMP while循环
我有一个运行多次迭代的代码,只有当满足一个条件时,迭代的结果才会被保存。这自然表示为while循环。我试图使代码并行运行,因为每个实现都是独立的。所以我有这个:Multithreading OpenMP while循环,multithreading,c++11,for-loop,while-loop,openmp,Multithreading,C++11,For Loop,While Loop,Openmp,我有一个运行多次迭代的代码,只有当满足一个条件时,迭代的结果才会被保存。这自然表示为while循环。我试图使代码并行运行,因为每个实现都是独立的。所以我有这个: while(nit<avit){ #pragma omp parallel shared(nit,avit) { //do some stuff if(condition){ #pragma omp critical {
while(nit<avit){
#pragma omp parallel shared(nit,avit)
{
//do some stuff
if(condition){
#pragma omp critical
{
nit++;
\\save results
}
}
}//implicit barrier here
}
正如预期的那样,它一直在for循环中运行,但是我的nit
变量采用了不可预测的值。。。正如我们可以预期的,在不同的时间,不同的线程会增加和减少它
我还尝试将for循环中的增量留空,但它不会编译,或者尝试欺骗我的代码,使其在for循环中没有增量,如
...
incr=0;
for(nit=0;nit<avit;nit+=incr)
...
。。。
增量=0;
对于(nit=0;nit您基本上可以遵循与for相同的概念,但略有不同,以确保avRes
不会并行写入:
int nit = 0;
#pragma omp parallel
while(1) {
int local_nit;
#pragma omp atomic read
local_nit = nit;
if (local_nit >= avit) {
break;
}
[...]
if (...) {
#pragma omp critical
{
#pragma omp atomic capture
local_nit = ++nit;
for(j=0;j<jmax;j++){
avRes[j] += Res[j];
}
for(j=0;j<jmax;j++){
// technically you could also use `nit` directly since
// now `nit` is only modified within this critical section
cout<<avRes[j]/local_nit<<"\t";
}
}
} else {
#pragma omp atomic update
dit++;
}
}
int nit=0;
#pragma-omp并行
而(1){
国际本地单位;
#pragma omp原子读取
本地_nit=nit;
如果(本地\u nit>=avit){
打破
}
[...]
如果(…){
#pragma-omp-critical
{
#pragma-omp原子捕获
本地_nit=++nit;
对于(j=0;如果对某些东西没有更具体的理解,jIt实际上不可能正确地回答这个问题。特别是我们不知道是否在某些东西中访问了nit
,以及当多个线程同时具有条件时会发生什么,或者当ne thread正在做一些事情…这很难,但要得到一个好的、具体的答案,你必须创建一个。感谢@Zulan的评论。我编辑了这个问题,在最后添加了一个最小的工作示例。希望这能澄清问题。感谢@Zulan,稍作修改,这看起来(几乎)是做这个把戏!我不太熟悉原子
,但它不允许我像关键
那样添加一块代码…我需要所有线程都能够编写结果,并且它们的编写频率比只在最后更高…如果我这样做的话(j=0;j请记住,我现在明白了atomic
只能用于单行指令。因此最后的代码必须有关键的部分用于编写。作为最后的更正,我相信local\u nit=nit++;
应该是nit++
,因为local\u nit
在上面是更新的#pragma omp atomic read local_nit=nit;
和阻止写入到结尾的if
。再次感谢您的帮助。我的代码错误地使用了后缀而不是前缀increment。我修复了它和链接。使用正确的形式local_nit=++nit;if(local_nit==avit)…
您可以在不使用昂贵的关键部分的情况下保护输出的写入。这更有意义…但这将再次只在程序结束时写入,对吗?我需要能够更频繁地检查结果,所以我想我确实需要一个关键部分…我可以“隐藏它”吗在一个if
?:#pragma omp原子捕获本地_wnit=++wnit;if(本地_wnit==wavit){#pragma omp critical{\\write;wnit-=local_wnit;}
其中wnit
是一个全局写入计数器local\u wnit
是一个本地处理的变量,wavit
是一个共享变量,具有写入事件之间的迭代次数。这会有帮助吗?还是相同?感谢修复链接。如果您需要更新每个增量的结果(抱歉,我误读了您的问题),您也可以只使用一个关键部分进行更新。请参阅我编辑的答案。或者,如果只是总结关键部分的性能问题,或者如果jmax
相当小,则可以进行缩减,以原子方式更新每个结果。最重要的是,您不想在关键部分读取计数器行动。
#include <random>
#include <vector>
#include <iostream>
#include <time.h>
#include <omp.h>
#include <stdlib.h>
#include <unistd.h>
using namespace std;
int main(){
int nit,dit,avit=100,t,j,tmax=100,jmax=10;
vector<double> Res(10),avRes(10);
nit=0; dit=0;
while(nit<avit){
#pragma omp parallel shared(tmax,nit,jmax,avRes,avit,dit) private(t,j) firstprivate(Res)
{
srand(int(time(NULL)) ^ omp_get_thread_num());
t=0; j=0;
while(t<tmax&&j<jmax){
Res[j]=rand() % 10;
t+=Res[j];
if(omp_get_thread_num()==5){
usleep(100000);
}
j++;
}
if(t<tmax){
#pragma omp critical
{
nit++;
for(j=0;j<jmax;j++){
avRes[j]+=Res[j];
}
for(j=0;j<jmax;j++){
cout<<avRes[j]/nit<<"\t";
}
cout<<" \t nit="<<nit<<"\t thread: "<<omp_get_thread_num();
cout<<endl;
}
} else{
#pragma omp critical
{
dit++;
cout<<"Discarded: "<<dit<<"\r"<<flush;
}
}
}
}
return 0;
}
int nit = 0;
#pragma omp parallel
while(1) {
int local_nit;
#pragma omp atomic read
local_nit = nit;
if (local_nit >= avit) {
break;
}
[...]
if (...) {
#pragma omp critical
{
#pragma omp atomic capture
local_nit = ++nit;
for(j=0;j<jmax;j++){
avRes[j] += Res[j];
}
for(j=0;j<jmax;j++){
// technically you could also use `nit` directly since
// now `nit` is only modified within this critical section
cout<<avRes[j]/local_nit<<"\t";
}
}
} else {
#pragma omp atomic update
dit++;
}
}