2015-04-07 2 views
1

У меня есть аналогичная проблема с вопросом, заданным здесь - OpenMP parallel thread. Я бы хотел распараллелить цикл for, включая std :: set iterator. Поэтому я пытаюсь изучить ответ, предоставленный @Hristo lliev. Что-то я не совсем уверен.OpenMP STL set container iterator

Если нить не подходит для выбора задачи, ее «худший_q» должен быть исходным номером, когда он входит в критический раздел. Но если поток выбирает задачу, а «t_worst_q» будет изменен внутри задачи, тогда, когда этот поток войдет в критический раздел, этот «t_worst_q» останется таким же, как и в конструкции задачи. Правильно ли? Тем не менее, я использовал пример, он не выглядит таким образом, может быть, я все еще что-то упускаю.

+1

Этот ответ был ужасно неправильным. Я только что исправил это. –

ответ

0

Да, как вы объясните, как «Христо Ильев» хотел, чтобы он работал. К сожалению, у него было несколько проблем с задачами:

Его так называемый «барьер» с использованием taskwait работает только для потока, создавшего задачи. Все остальные потоки проходят через него. Поэтому его полное сокращение в конце бесполезно, потому что большинство потоков выполняют его до, они фактически выполняют любую работу. «Taskwait» был разработан, чтобы помочь учитывать зависимости данных (очень полезно in recursive functions!), Поэтому он работает так, как он делает.

Единственная причина, по которой программа работает иногда даже без функционального сокращения в конце, заключается в том, что его первая ошибка частично отменена второй ошибкой: переменная t_worst_q в задаче ссылается на одну из потока, который сгенерирован задача и, следовательно, действует как глобальная переменная. Но тогда, конечно, у нас есть условие гонки в std::min, что по-прежнему позволяет сбой кода иногда.

Таким образом, в силу его код эквивалентен следующему:

#pragma omp parallel 
{ 
    // Create tasks 
    #pragma omp single nowait 
    { 
     for(std::set<size_t>::const_iterator it=mesh->NEList[vid].begin(); 
      it!=mesh->NEList[vid].end(); ++it) { 
     size_t elem = *it; 
     #pragma omp task shared(worst_q) 
     worst_q = std::min(worst_q, mesh->element_quality(elem)); 
     } 
    } 
} 

Это, как было сказано выше, имеет проблему наличия условия гонки в доступе к worst_q при выполнении std::min. Если функция mesh->element_quality является вычислительно дорогой по сравнению с функцией std::min, то простым решением является критический участок вокруг части std::min (после выполнения mesh->element_quality вне критической секции). Если, с другой стороны, mesh->element_quality не дороже, чем std::min, то критическая секция убьет параллельность. Но в этом случае функция mesh->element_quality настолько дешева, что накладные расходы на управление задачами все равно съедят все возможные ускорения.