Передача данных с помощью директивы threadprivate
В этом же разделе внимание сфокусировано на проблеме передачи данных между параллельными потоками из одного параллельного структурного блока программы в другой, минуя промежуточный последовательный структурный блок. Для реализации такого механизма передачи данных в OpenMP имеется специальная директива threadprivate.
Директива threadprivate применяется к глобальным переменным программы, которые нужно сделать локальными переменными для каждого из параллельных потоков. Кроме того, эта директива позволяет передавать локальные данные из одного параллельного структурного блока в другой, а также сохранять локальные данные из параллельных потоков на протяжении всей программы.
В программах, написанных на языке C/C++, предложение threadprivate имеет следующий вид:
#pragma omp threadprivate(var)
var
A comma-separated list of variables that you want to make private to a thread. var must be either a global- or namespace-scoped variable or a local static variable.
Отметим, что элементами списка не могут быть ссылки или переменные, не полностью определенные. Кроме того, адреса констант также недопустимы в списке.
Все переменные, включенные в список директив threadprivate, должны быть проинициализированы до начала первого параллельного блока, и их инициализация возможна только один раз на протяжении всей программы. Кроме того, переменные, включенные в список, не могут фигурировать в других предложениях OpenMP, за исключением copyin, schedule или if. Категорически запрещено их использование в директивах private, firstprivate, lastprivate, shared и reduction.
Не допускается применение передачи значений переменных из одного параллельного структурного блока в другой в динамическом (dynamic) режиме работы параллельной программы. На всем протяжении действия директивы threadprivate должен быть установлен статический режим работы параллельной программы.
Ниже приведен пример фрагмента параллельной программы, написанной на языке C/C++ с использованием директивы OpenMP threadprivate. В этом примере для отмены динамического режима явно вызывается функция из библиотеки реального времени runtime OpenMP omp_set_dynamic с параметром 0.
#include <omp.h> int alpha [10], beta[10], i; #pragma omp threadprivate (alpha) main ( ){/*Выключение динамического режима*/ omp_set_dynamic (0); /*1-й параллельный блок */ #pragma omp parallel private (i, beta) for (i=0; i<10; i++) alpha[i] = beta[i] = i; /*2-й параллельный блок*/ #pragma omp parallel printf ("alpha[3]=%d and beta [3] =%d\n", alpha[3], beta[3]);}Если изменить значение переменной, объявленной как threadprivate, начальное значение переменной в параллельной секции окажется непредсказуемым.
Приведем пример.
Некорректно:
int a = 5; #pragma omp threadprivate(a) int _tmain(int argc, _TCHAR* argv[]) { ... a = 10; #pragma omp parallel num_threads(2) { #pragma omp critical { printf("nThread #%d: a = %d", omp_get_thread_num(),a); } } getchar(); return 0; } |
В результате выполнения этого кода один из потоков выведет значение 5, а другой выведет 10. Если убрать инициализацию переменной а до директивы threadprivate, один из потоков начнет выводить 0, а второй – по-прежнему 10. Избавиться от непредсказуемого поведения удастся лишь убрав второе присваивание. В этом случае оба потока будут выводить значение 5 (если первое присваивание все же оставить). Конечно, такие исправления изменят поведение кода.
Авторы [2] вообще от использования этой директивы советуют отказаться. В этом случае код станет намного более предсказуемым и понятным.
Корректно:
int a = 5; int _tmain(int argc, _TCHAR* argv[]) { ... a = 10; #pragma omp parallel num_threads(2) { int a = 10; #pragma omp barrier #pragma omp critical { printf("nThread #%d: a = %d", omp_get_thread_num(),a); } } getchar(); return 0; } |
Дата добавления: 2015-02-03; просмотров: 1377;