довольно мало, каждый результат обновляется атомарно. Самое главное, вы не хотите читать счетчик в критическом разделе.
я есть код, который выполняет много итераций, и только если условие выполняется, результат итерации сохраняется. Это естественно выражается как цикл while. Я пытаюсь заставить код работать параллельно, так как каждая реализация независима. Итак, у меня есть это:
while(nit<avit){
#pragma omp parallel shared(nit,avit)
{
//do some stuff
if(condition){
#pragma omp critical
{
nit++;
\\save results
}
}
}//implicit barrier here
}
и это работает нормально ... но после каждой реализации есть барьер, что означает, что если то, что я делаю в параллельном блоке, занимает больше времени в одной итерации, чем другие, все мои потоки ждут его завершения, а не продолжая следующую итерацию.
Есть ли способ избежать этого барьера, чтобы потоки продолжали работать? Я в среднем тысячи итераций, так что еще несколько не больно (в случае, еслиnit
переменная не была увеличена в уже запущенных потоках) ...
Я пытался превратить это в параллель для, но автоматическое увеличение цикла for делаетnit
переменная сходит с ума. Это моя попытка:
#pragma omp parallel shared(nit,avit)
{
#pragma omp for
for(nit=0;nit<avit;nit++){
//do some stuff
if(condition){
\\save results
} else {
#pragma omp critical
{
nit--;
}
}
}
}
и он продолжает работать и обходить цикл, как и ожидалось, но мойnit
переменная принимает непредсказуемые значения ... как можно было ожидать от увеличения и уменьшения ее различными потоками в разное время.
Я также пытался оставить приращение в цикле for пустым, но он не компилируется, или пытался обмануть мой код, чтобы не иметь приращения в цикле for, например
...
incr=0;
for(nit=0;nit<avit;nit+=incr)
...
но тогда мой код вылетает ...
Есть идеи?
Спасибо
Изменить: Вот рабочий минимальный пример кода в цикле while:
#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;
}
Я добавилusleep
часть для имитации одного потока, занимающего больше времени, чем другие. Если вы запустите программу, все потоки должны ждать завершения потока 5, а затем они начнут следующий запуск. то, что я пытаюсь сделать, - это точно избежать такого ожидания, то есть я бы хотел, чтобы другие потоки выбрали следующую итерацию, не дожидаясь окончания 5.