Главная / Программирование / Параллельное программирование с OpenMP

Параллельное программирование с OpenMP - ответы на тесты Интуит

Правильные ответы выделены зелёным цветом.
Все ответы: В рамках курса проводится изучение основных возможностей стандарта OpenMP, необходимых для создания эффективных параллельных программ для многоядерных и многопоточных процессоров. Рассматриваются подходы для функциональной отладки OpenMP-программ, а также отладки эффективности.
Смотрите также:
Строгая модель консистентности памяти определяется следующим условием:
(1) все обращения к ячейкам памяти абсолютно упорядочены во времени
(2) все процессы наблюдают все обращения к ячейкам памяти в одном и том же порядке. Обращения не упорядочены по времени
(3) все процессы наблюдают все обращения к ячейкам памяти, связанные причинно-следственной связью в одном и том же порядке
Использование операторов перехода (goto) в структурном блоке OpenMP возможно:
(1) если оператор перехода не выводит за пределы блока
(2) поскольку в стандарте нет никаких ограничений на операторы перехода
(3) в некоторых OpenMP-компиляторах (зависит от реализации)
Найдите ошибку в следующем фрагменте программы: #pragma omp parallel default(shared) { int i, j; #pragma omp for for (i=0; i<n; i++) { #pragma omp for for (j=0; j<n; j++) work(i, j); } }
(1) используются конструкции распределения работ, которые непосредственно вложены одна в другую
(2) в результате использования клаузы default(shared), счетчики циклов i и j являются общими для всех нитей
(3) в данном фрагменте программы ошибки нет
Директива master
(1) определяет блок операторов в программе, который будет выполнен одной нитью группы. Остальные нити группы дожидаются завершения выполнения этого блока
(2) определяет блок операторов в программе, который будет выполнен master-нитью. Остальные нити группы дожидаются завершения выполнения этого блока
(3) определяет блок операторов в программе, который будет выполнен master-нитью. Остальные нити группы не дожидаются завершения выполнения этого блока
Определите способ распределения витков цикла между нитями для следующего фрагмента программы: #define N 100 void work(int i); int main () { #pragma omp parallel { #pragma omp for for (int i=0;i<N;i++) work (i); } }
(1) статический (static)
(2) зависит от значения переменной окружения OMP_SCHEDULE
(3) зависит от реализации компилятора
Найдите ошибку в следующем фрагменте программы: #define N 1000 int main (void){ float a[N], tmp; #pragma omp parallel { #pragma omp for for(int i=0; i<N;i++) { tmp= a[i]*a[i]; a[i]=1-tmp; } } }
(1) в директиве for отсутствует клауза private(i)
(2) в директиве for отсутствует клауза private(tmp)
(3) в данном фрагменте программы ошибки нет
Выберите наилучшую стратегию распределения витков цикла между нитями, которая для следующего фрагмента программы даст минимальное время выполнения: #include <omp.h> #include <unistd.h> #define msec 1000 int main (void){ omp_set_num_threads (8); #pragma omp parallel { #pragma omp for schedule (runtime) for(int i=0; i<100;i++) { sleep (i*msec); } } }
(1) export OMP_SCHEDULE=”static”
(2) export OMP_SCHEDULE=”static,10”
(3) export OMP_SCHEDULE=”dynamic”
Директива SHARABLE в технологии Intel Cluster OpenMP:
(1) определяет разделяемые нитями переменные, доступ к которым возможен только на одном из узлов кластера
(2) определяет разделяемые нитями переменные, доступ к которым обрабатывается механизмом DSM
(3) задает, какие переменные, на какой узел кластера необходимо отобразить
PRAM модель консистентности памяти определяется следующим условием:
(1) все процессы наблюдают все обращения к ячейкам памяти в одном и том же порядке. Обращения не упорядочены по времени
(2) все процессы наблюдают все обращения к ячейкам памяти, связанные причинно-следственной связью в одном и том же порядке
(3) все процессы наблюдают операции записи любого процесса в порядке их выполнения. Операции записи различных процессов могут наблюдаться разными процессами в разном порядке
Параллельная область в OpenMP создается при помощи:
(1) вызова функции omp_set_max_active_levels
(2) вызова функции omp_set_num_threads
(3) директивы parallel
Найдите ошибку в следующем фрагменте программы: int i, j; #pragma omp parallel default(shared) { #pragma omp for collapse (3) for (i=0; i<n; i++) { for (j=0; j < n; j++) work(i, j); } }
(1) в результате использования клаузы default(shared), счетчики циклов - переменные i и j являются общими для всех нитей
(2) количество заголовков циклов не соответствуют значению, указанному в клаузе collapse
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: #define N 10 int A[N],B[N]; #pragma omp parallel default(shared) { int i; #pragma omp master for (i=0; i<N; i++) { A[i]=0; } #pragma omp barrier B[N-1]=B[N-1] + A[N-1]; }
(1) оператор for не может быть использован внутри конструкции master
(2) оператор, в котором изменяется значение общей переменной B[N-1] выполняется без какой-либо синхронизации
(3) в данном фрагменте программы ошибки нет
Определите способ распределения витков цикла между нитями для следующего фрагмента программы: #define N 100 #include "omp.h" void work(int i); int main () { #pragma omp parallel { omp_set_schedule (omp_sched_static); #pragma omp for for (int i=0;i<N;i++) work (i); } }
(1) статический (static)
(2) зависит от значения переменной окружения OMP_SCHEDULE
(3) зависит от реализации компилятора
Найдите ошибку в следующем фрагменте программы: int main (void){ int a, i; #pragma omp parallel shared(a) private(i) { #pragma omp master a = 0; #pragma omp for reduction(+:a) for (i = 0; i < 10; i++) { a += i; } } }
(1) в директиве parallel клауза shared(a) должна быть заменена на private(a)
(2) перед директивой for отсутствует директива barrier
(3) в данном фрагменте программы ошибки нет
Выберите наилучшую стратегию распределения витков цикла между нитями, которая для следующего фрагмента программы даст минимальное время выполнения: #include <omp.h> #include <unistd.h> #define msec 1000 int main (void){ omp_set_num_threads (8); #pragma omp parallel { #pragma omp for schedule (runtime) for(int i=0; i<80;i++) { sleep (msec); } } }
(1) export OMP_SCHEDULE=”static,10”
(2) export OMP_SCHEDULE=”static,15”
(3) export OMP_SCHEDULE=”static,20”
Использование технологии Intel Cluster OpenMP целесообразно:
(1) для OpenMP-программ, с хорошей локализацией данных и требующих малой синхронизации
(2) для OpenMP-программ с нерегулярными вычислениями, проводимыми над общими данными
(3) для любых OpenMP-программ
Пусть W(x)a – операция записи в переменную x значения a. Пусть R(x)a – операция чтения переменной x, где a – прочитанное значение переменной x. Пусть S - операция синхронизации. Следующая последовательность событий:
P1: W(x)aW(x)bS
P2:R(x)aR(x)bS
P3:R(x)bR(x)aS
(1) допустима при слабой модели консистентности
(2) не допустима при слабой модели консистентности
(3) допустима при модели консистентности по выходу
При реализации компилятором редукционного оператора, описанного при помощи клаузы reduction (+: sum), где переменная sum имеет тип integer, для каждой нити создается локальная копия переменной sum, начальное значение которой будет инициализировано:
(1) 0
(2) -MAXINT (минимально возможное целое число)
(3) MAXINT (максимально возможное целое число)
Найдите ошибку в следующем фрагменте программы: #define N 10 float c[N]; float sum = 0.0; #pragma omp parallel shared(sum, c) { #pragma omp for reduction (+: sum) nowait for (int i=0; i<N; i++) { sum += c[i]; } #pragma omp single printf (“Sum of array=%4.2f\n”, sum); }
(1) редукционная переменная sum объявлена общей(shared)
(2) в директиве for нельзя одновременно указать клаузу reduction и клаузу nowait
(3) до использования значения редукционной переменной sum в операторе печати в блоке single отсутствует барьерная синхронизация нитей
Найдите ошибку в следующем фрагменте программы: #define N 10 int A[N],B[N], sum; #pragma omp parallel default(shared) num_threads(10) { int iam=omp_get_thread_num(); if (A[iam] > 0) { #pragma omp critical (update_a) sum +=A[iam]; } if (B[iam] > 0) { #pragma omp critical (update_b) sum +=B[iam]; } }
(1) чтение общих переменных А[iam] и B[iam] в операторах вида A[iam]>0 и B[iam]>0 выполняется без какой-либо синхронизации
(2) изменение общей переменной sum внутри критических секций update_a и update_b может выполняться одновременно несколькими нитями, поскольку названия критических секций отличаются
(3) в данном фрагменте программы ошибки нет
Определите количество нитей, между которыми будет распределена работа в параллельной области: #define N 100 #include "omp.h" void work(int i); int main () { omp_set_num_threads(2); #pragma omp parallel num_threads(4) { #pragma omp for for (int i=0;i<N;i++) work (i); } }
(1) 2
(2) 4
(3) зависит от значения переменной окружения OMP_NUM _THREADS
Найдите ошибку в следующем фрагменте программы: #include <omp.h> int numproc; #pragma omp threadprivate(numproc) int main (void){ numproc=omp_get_num_procs(); #pragma omp parallel { if (numproc < 4) do_small_work(); else do_big_work (); } }
(1) функция omp_get_num_procs не может быть вызвана вне параллельной области
(2) в директиве parallel отсутствует клауза copyin(numproc)
(3) в данном фрагменте программы ошибки нет
Выберите наиболее походящую оптимизацию, которая позволит сократить время выполнения следующего фрагмента программы: #include <omp.h> #include <stdio.h> #define N 100 float c[N]; float sum = 0.0; int main (void) { omp_set_num_threads (8); #pragma omp parallel shared(sum, c) { #pragma omp for for (int i=0; i<N; i++) { #pragma omp critical sum += c[i]; } } printf (“Sum of array=%4.2f\n”, sum); }
(1) заменить директиву critical на директиву atomic
(2) заменить директиву critical на директиву critical (<имя_критической_секции>)
(3) добавить к директиве for клаузу reduction(+:sum) и убрать директиву critical
Технология OpenMP по сравнению с MPI имеет следующие преимущества (отметьте все подходящие варианты):
(1) возможность инкрементального распараллеливания
(2) ликвидация дублирования данных в памяти (массивов констант, теневых граней и т.п.)
(3) упрощение программирования и эффективность на нерегулярных вычислениях, проводимых над общими данными
Найдите ошибку в следующем фрагменте программы: #define N 10 int i; #pragma omp parallel { int tmp = 0; #pragma omp for private(tmp) for (i=0; i<N; i++) { tmp += i; } }
(1) не определен класс для переменной i (отсутствует клауза private (i))
(2) начальное значение переменной tmp в параллельном цикле не определено
(3) в данном фрагменте программы ошибки нет
Клауза copyin:
(1) может быть использована только для переменных, указанных в клаузе private
(2) может быть использована только для переменных, указанных в директиве threadprivate
(3) может быть использована как для переменных указанных в директиве threadprivate, так и для переменных, указанных в клаузе private
Найдите ошибку в следующем фрагменте программы: #pragma omp parallel default(shared) { int i; #pragma omp for lastprivate(i) for (i=0; i!=n; i++) { work(i); } }
(1) в заголовке цикла, витки которого распределяются между нитями при помощи директивы for вместо оператора отношения (типа <,<=,>,>=) указан оператор сравнения (!=)
(2) индексная переменная цикла, витки которого распределяются между нитями при помощи директивы for, не может быть указана в клаузе lastprivate
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: int numt=0; #pragma omp parallel { #pragma omp master { #pragma omp critical { numt=omp_get_num_threads(); } #pragma omp barrier } }
(1) директива barrier не может быть использована внутри конструкции master
(2) директива critical не может быть использована внутри конструкции master;
(3) в данном фрагменте программы ошибки нет
Пусть следующая программа скомпилирована компилятором, поддерживающим вложенный параллелизм. #include <stdio.h> #include "omp.h" int counter; int main() { counter=0; omp_set_nested(0); #pragma omp parallel num_threads(2) { if (omp_get_thread_num() == 0) { #pragma omp parallel num_threads(2) { #pragma omp atomic counter++; } } } printf("Counter=%d\n",counter); } Определите значение переменной counter по завершении выполнения этой программы:
(1) 1
(2) 2
(3) 4
Найдите ошибку в следующем фрагменте программы: #pragma omp parallel { int me; me = omp_get_thread_num (); if (me == 0) goto Master; #pragma omp barrier Master: #pragma omp single }
(1) в директиве parallel отсутствует клауза private(me)
(2) дедлок - взаимная блокировка нитей, возникающая в результате того что master-нить не попадает на директиву barrier
(3) оператор goto не может быть использован внутри конструкции parallel
Выберите наиболее походящую оптимизацию, которая позволит сократить время выполнения следующего фрагмента программы: #include <omp.h> #include <unistd.h> #define msec 1000 int main (void){ omp_set_num_threads (8); #pragma omp parallel { #pragma omp for for(int i=0; i<80;i++) { sleep (i*msec); } #pragma omp for for(int i=0; i<80;i++) { sleep ((80-i)*msec); } } }
(1) для циклов, выполнение витков которых распределяется между нитями при помощи директивы for, добавить клаузу schedule(static,10)
(2) для циклов, выполнение витков которых распределяется между нитями при помощи директивы for, добавить клаузу nowait
(3) для циклов, выполнение витков которых распределяется между нитями при помощи директивы for, добавить клаузу schedule(dynamic)
Найдите ошибку в следующем фрагменте MPI/OpenMP-программы, вычисляющей число Пи: #include <mpi.h> #include <omp.h> #define num_steps 100000 void main (int argc, char *argv[]) { double pi, step, sum = 0.0 ; step = 1.0/(double) num_steps ; #pragma omp parallel { int numprocs, myid, mysteps; MPI_Init(&argc, &argv) ; MPI_Comm_Rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_Size(MPI_COMM_WORLD, &numprocs) ; mysteps = num_steps/numprocs ; #pragma omp for reduction(+:sum) for (int i=myid*mysteps; i<(myid+1)*mysteps ; i++){ double x = (i+0.5)*step; sum += 4.0*step/(1.0+x*x); } MPI_Reduce(&sum, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); } MPI_Finalize(); }
(1) все обращения к MPI-функциям в параллельной области должны выполняться одной нитью (например, внутри конструкции single)
(2) переменные numprocs, myid, mysteps должны быть объявлены как private(numprocs, myid, mysteps)
(3) в данном фрагменте программы ошибки нет
Определите класс по умолчанию для переменной numt: int i=0; int numt = omp_get_max_threads(); #pragma omp parallel for for(i=0; i< numt; i++) Work(i);
(1) private
(2) shared
(3) threadprivate
Рассмотрим фрагмент OpenMP-программы: #include <omp.h> int n=1; int main (void) { omp_set_nested(1); omp_set_dynamic(1); omp_set_num_threads(2); #pragma omp parallel if (n>10) {/*параллельная область*/ … } } Для выполнения параллельной области будет создана группа нитей, состоящая из:
(1) 1-ой нити
(2) 2-х нитей
(3) нескольких нитей (количество создаваемых нитей зависит от переменной окружения OMP_NUM_THREADS)
Способ распределения витков цикла между нитями группы задается при помощи клаузы schedule(<алгоритм планирования>[,<число итераций>]). Найдите ошибку в следующем фрагменте программы: #pragma omp parallel default(shared) { int i; #pragma omp for schedule(static, omp_get_thread_num()) for (i=0; i<n; i++) { work(i); } }
(1) значение параметра <число итераций> клаузы schedule отличается для каждой нити группы
(2) при статическом планировании, задаваемом клаузой schedule(static), параметр <число итераций> задать нельзя
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: #include <math.h> double x=1024.0; int n=1024; #pragma omp parallel { #pragma omp atomic x+=sqrt(x); #pragma omp atomic n&=0177; }
(1) при вычислении выражения в правой части оператора присваивания, указанного в конструкции atomic, не может быть использована переменная, указанная в левой части оператора присваивания
(2) оператор & (побитовое И) не может быть использован в конструкции atomic
(3) в данном фрагменте программы ошибки нет
Определите значение переменной team_size по завершении выполнения следующей программы: #include <stdio.h> #include "omp.h" int main() { int team_size; team_size=omp_get_team_size(omp_get_level ()); printf("Team Size=%d\n",team_size); }
(1) -1
(2) 0
(3) 1
Поиск ошибок в OpenMP-программе, выполняемый Intel Thread Checker, основан на:
(1) методе статического анализа кода программы
(2) методе динамического анализа корректности программы
(3) методе сравнительной отладки нескольких запусков одной программы
Выберите наиболее походящую оптимизацию, которая позволит сократить время выполнения следующего фрагмента программы: #include <omp.h> #include <unistd.h> #define msec 1000 int main (void){ int i; omp_set_num_threads (8); #pragma omp parallel for for (i=0; i<80; i++) sleep (msec); #pragma omp parallel for for (i=0; i<80; i++) sleep (msec); }
(1) для первого цикла, выполнение витков которого распределяется между нитями при помощи директивы for, добавить клаузу schedule(dynamic)
(2) для второго цикла, выполнение витков которого распределяется между нитями при помощи директивы for, добавить клаузу schedule(dynamic)
(3) объединить две подряд стоящие параллельные области в одну
Найдите ошибку в следующем фрагменте MPI/OpenMP-программы, реализующей метод релаксации Якоби: int jacobi(int p, int id, int my_rows, double **u, double **w) { double diff, global_diff, tdiff; int i,j,it; MPI_Status status; it=0; for(;;) { if (id>0) MPI_Send (u[1], N, MPI_DOUBLE, id-1, 0, MPI_COMM_WORLD); if (id<p-1) { MPI_Send (u[my_rows-2], N, MPI_DOUBLE, id+1, 0, MPI_COMM_WORLD); MPI_Recv (u[my_rows-1], N, MPI_DOUBLE, id+1, 0, MPI_COMM_WORLD, &status); } if (id>0) MPI_Recv (u[0], N, MPI_DOUBLE, id-1, 0, MPI_COMM_WORLD, &status); diff=0.0; #pragma omp parallel private (i,j,tdiff) { tdiff=0.0; #pragma omp for for (i=1; i<my_rows; i++) for (j=1; j<N-1; j++) { w[i][j]=(u[i-1][j]+u[i+1][j]+u[i][j-1]+u[i][j+1])/4.0; if (fabs(w[i][j]-u[i][j]) >tdiff) tdiff=fabs(w[i][j]-u[i][j]); } #pragma omp for nowait for (i=1; i<my_rows; i++) for (j=1; j<N-1; j++) u[i][j]=w[i][j]; if (tdiff > diff) diff=tdiff; } MPI_Allreduce (&diff, &global_diff, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); if (global_diff <= EPSILON) break; it++; } return it; }
(1) не определен класс для переменных u, w, my_rows, diff, используемых в параллельной области -shared(u,w,my_rows,diff)
(2) конфликт доступа к данным (race condition), возникающий в результате выполнения оператора if (tdiff > diff) diff=tdiff в параллельной области без какой-либо синхронизации
(3) в данном фрагменте программы ошибки нет
Последовательная модель консистентности памяти определяется следующим условием:
(1) все обращения к ячейкам памяти абсолютно упорядочены во времени
(2) все процессы наблюдают все обращения к ячейкам памяти в одном и том же порядке. Обращения не упорядочены по времени
(3) все процессы наблюдают все обращения к ячейкам памяти, связанные причинно-следственной связью в одном и том же порядке
Использование оператора exit в структурном блоке OpenMP:
(1) запрещено в стандарте
(2) разрешено в стандарте
(3) возможно в некоторых OpenMP-компиляторах (зависит от реализации)
Найдите ошибку в следующем фрагменте программы: #pragma omp parallel default(shared) { int i, j; #pragma omp for for (i=0; i<n; i++) { #pragma omp parallel { #pragma omp for shared (i,n) for (j=0; j<n; j++) work(i, j); } } }
(1) используются конструкции распределения работ, которые вложены одна в другую
(2) клауза shared не может быть использована в директиве for
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: #define N 10 int A[N],B[N]; #pragma omp parallel default(shared) { int i; ..…#pragma omp master for (i=0; i<N; i++) { A[i]=0; } #pragma omp for for (i=0; i<N; i++) B[i]=A[i]; }
(1) оператор for не может быть использован внутри конструкции master
(2) по завершении конструкции master отсутствует директива barrier
(3) в данном фрагменте программы ошибки нет
Определите способ распределения витков цикла между нитями для следующего фрагмента программы: #define N 100 #include "omp.h" void work(int i); int main () { #pragma omp parallel { omp_set_schedule (omp_sched_dynamic); #pragma omp for schedule(static) for (int i=0;i<N;i++) work (i); } }
(1) статический (static)
(2) динамический (dynamic)
(3) зависит от значения переменной окружения OMP_SCHEDULE.
Найдите ошибку в следующем фрагменте программы: #define N 1000 int main (void){ float a[N]; #pragma omp parallel { #pragma omp for for(int i=0; i<N;i++) { float tmp; tmp= a[i]*a[i]; a[i]=1-tmp; } } }
(1) в директиве for отсутствует клауза private(i)
(2) в директиве for отсутствует клауза private(tmp)
(3) в данном фрагменте программы ошибки нет
Выберите наилучшую стратегию распределения витков цикла между нитями, которая для следующего фрагмента программы даст минимальное время выполнения: #include <omp.h> #include <unistd.h> #define msec 1000 int main (void){ omp_set_num_threads (8); #pragma omp parallel { #pragma omp for schedule (runtime) for(int i=0; i<100;i++) { sleep ((100-i)*msec); } } }
(1) export OMP_SCHEDULE=”static”
(2) export OMP_SCHEDULE=”static,10”
(3) export OMP_SCHEDULE=”dynamic”
Для выделения памяти для SHARABLE-переменных в технологии Intel Cluster OpenMP требуется использовать:
(1) обычные функции malloc, realloc и т.д
(2) специальные функции kmp_sharable_malloc, kmp_sharable_realloc и т.д
(3) как обычные, так и специальные функции. Доступ к переменным, для которых память выделена при помощи специальных функций осуществляется быстрее
Процессорная модель консистентности памяти определяется следующим условием:
(1) все процессы наблюдают все обращения к ячейкам памяти в одном и том же порядке. Обращения не упорядочены по времени
(2) все процессы наблюдают операции записи любого процесса в порядке их выполнения. Операции записи различных процессов могут наблюдаться разными процессами в разном порядке
(3) все процессы наблюдают операции записи любого процесса в порядке их выполнения. Для каждой переменной существует общее согласие относительно порядка, в котором процессы модифицируют эту переменную. Операции записи различных процессов могут наблюдаться разными процессами в разном порядке
Функция omp_get_num_threads возвращает:
(1) количество нитей в текущей параллельной области
(2) максимально возможное количество нитей, которые могут быть использованы при выполнении всей программы
(3) номер нити в группе
Найдите ошибку в следующем фрагменте программы: int i, j; #pragma omp parallel default(shared) { #pragma omp for collapse (2) for (i=0; i<n; i++) { work_with_i (i); for (j=0; j < n; j++) work(i, j); } }
(1) в результате использования клаузы default(shared), счетчики циклов - переменные i и j являются общими для всех нитей
(2) между заголовками циклов указан вызов процедуры work_with_i (клауза collapsе может быть использована только распределения витков тесно-вложенных циклов)
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: #define N 10 int A[N],B[N],tmp; #pragma omp parallel default(shared) num_threads(10) { int iam=omp_get_thread_num(); tmp=A[iam]; B[iam]=tmp; }
(1) изменение общей переменной B[iam] выполняется без какой-либо синхронизации
(2) чтение/изменение общей переменной tmp выполняется без какой-либо синхронизации
(3) в данном фрагменте программы ошибки нет
Определите способ распределения витков цикла между нитями для следующего фрагмента программы: #define N 100 #include "omp.h" void work(int i); int main () { #pragma omp parallel { omp_set_schedule (omp_sched_dynamic); #pragma omp for for (int i=0;i<N;i++) work (i); } }
(1) динамический (dynamic)
(2) зависит от значения переменной окружения OMP_SCHEDULE
(3) зависит от реализации компилятора
int main (void){ int a, i; #pragma omp parallel shared(a) private(i) { #pragma omp single a = 0; #pragma omp for for (i = 0; i < 10; i++) { a += i; } } }
(1) перед директивой for отсутствует директива barrier
(2) в директиве for отсутствует клауза reduction(+:a)
(3) в данном фрагменте программы ошибки нет
Выберите наилучшую стратегию распределения витков цикла между нитями, которая для следующего фрагмента программы даст минимальное время выполнения: #include <omp.h> #include <unistd.h> #define msec 1000 int main (void){ omp_set_num_threads (4); #pragma omp parallel { #pragma omp for schedule (runtime) for(int i=0; i<40;i++) { sleep (msec); } } }
(1) export OMP_SCHEDULE=”static,10”
(2) export OMP_SCHEDULE=”dynamic,15”
(3) export OMP_SCHEDULE=”static,20”
При использовании технологии Intel Cluster OpenMP программист:
(1) при помощи соответствующих директив распределяет по узлам кластера разделяемые нитями переменные и вычисления, проводимые над этими переменными
(2) при помощи соответствующих директив определяет разделяемые нитями переменные, доступ к которым обрабатывается механизмом DSM. Вычисления распределяются по узлам кластера компилятором
(3) при помощи соответствующих директив распределяет вычисления по узлам кластера. Данные по узлам кластера распределяются в соответствии с распределением вычислений
Пусть W(x)a – операция записи в переменную x значения a. Пусть R(x)a – операция чтения переменной x, где a – прочитанное значение переменной x. Пусть S - операция синхронизации. Следующая последовательность событий:
P1: W(x)aW(x)bS
P2:SR(x)a
(1) допустима при слабой модели консистентности
(2) не допустима при слабой модели консистентности
(3) допустима при модели консистентности по выходу
При реализации компилятором редукционного оператора, описанного при помощи клаузы reduction (*: prod), где переменная prod имеет тип integer, для каждой нити создается локальная копия переменной prod, начальное значение которой будет инициализировано:
(1) 1
(2) 0
(3) MAXINT (максимально возможное целое число)
Найдите ошибку в следующем фрагменте программы: #define N 10 int i; #pragma omp parallel { #pragma omp for firstprivate(i) lastprivate(i) for (i=0; i<N; i++) { … } #pragma omp single printf (“Number of iteration=%d\n”, i); }
(1) одна и та же переменная не может быть указана в клаузах firstprivate и lastprivate одновременно
(2) индексная переменная цикла, витки которого распределяются между нитями при помощи директивы for, не может быть указана в клаузе firstprivate
(3) индексная переменная цикла, витки которого распределяются между нитями при помощи директивы for, не может быть указана в клаузе lastprivate
Найдите ошибку в следующем фрагменте программы: #define N 10 int A[N],B[N], sum; #pragma omp parallel default(shared) num_threads(10) { int iam=omp_get_thread_num(); if (iam ==0) { #pragma omp critical (update_a) #pragma omp critical (update_b) sum +=A[iam]; } else { #pragma omp critical (update_b) #pragma omp critical (update_a) sum +=B[iam]; } }
(1) критические секции, определяемые директивой critical, не могут быть вложены друг в друга
(2) дедлок - взаимная блокировка нитей, возникающая при входе master-нитью в критическую секцию с именем update_a и любой другой нитью в секцию с именем update_b (в этом случае вложенные критические секции не смогут быть обработаны)
(3) в данном фрагменте программы ошибки нет
Определите количество нитей, между которыми будет распределена работа в параллельной области: #include "omp.h" void work(int i); int main () { int n; n=10; omp_set_num_threads(2); #pragma omp parallel num_threads(4) if (n>20) { #pragma omp for for (int i=0;i<n;i++) work (i); } }
(1) 1
(2) 2
(3) 4
Найдите ошибку в следующем фрагменте программы: #include <omp.h> int main (void){ #pragma omp parallel { int numt; #pragma omp single numt=omp_get_num_threads(); if (numt < 4) do_small_work(); else do_big_work (); } }
(1) после конструкции single отсутствует директива barrier
(2) в директиве single отсутствует клауза copyprivate(numt)
(3) в данном фрагменте программы ошибки нет
Выберите наиболее походящую оптимизацию, которая позволит сократить время выполнения следующего фрагмента программы: #include <omp.h> #include <stdio.h> #define N 100 int c[N]; int val = 0; int main (void) { omp_set_num_threads (8); #pragma omp parallel shared(val, c) { #pragma omp for for (int i=0; i<N; i++) { #pragma omp critical val ^= c[i]; } } printf (“Result=%d\n”, var); }
(1) заменить директиву critical на директиву critical (<имя_критической_секции>)
(2) заменить директиву critical на директиву atomic
(3) добавить к директиве for клаузу reduction(^:val) и убрать директиву critical
При использовании гибридной модели параллельного программирования MPI/OpenMP:
(1) все нити взаимодействуют друг с другом только через обмены сообщений
(2) все нити, выполняемые на узле кластера, взаимодействуют через общую память, а MPI используется для обмена информацией между узлами кластера
(3) все нити, выполняемые на различных узлах кластера, взаимодействуют друг с другом через общую память
Найдите ошибку в следующем фрагменте программы: #define N 10 int i; int tmp = 0; #pragma omp parallel { #pragma omp for firstprivate(tmp) lastprivate(tmp) for (i=0; i<N; i++) { if (i != N - 1 ) tmp += i; } }
(1) одна и та же переменная не может быть указана в клаузах firstprivate и lastprivate одновременно
(2) не определен класс для переменной i (отсутствует клауза private (i))
(3) по завершении выполнения цикла значение переменой tmp не определено
Клауза num_threads задает:
(1) максимально возможное число нитей, которые будут созданы при входе в параллельную область
(2) число нитей, которые обязательно будут созданы при входе в параллельную область
(3) максимально возможное количество нитей, которые могут быть использованы при выполнении всей программы
Найдите ошибку в следующем фрагменте программы: #pragma omp parallel default(shared) { int i; #pragma omp for lastprivate(i) for (i=0; i<n; i++) { i+=2; work(i); } }
(1) индексная переменная цикла, витки которого распределяются между нитями при помощи директивы for, не может быть указана в клаузе lastprivate
(2) изменение значения индексной переменной цикла for внутри цикла (при помощи оператора i+=2) не допускается
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: int numt=0; #pragma omp parallel { #pragma omp single { #pragma omp critical { numt=omp_get_num_threads(); } #pragma omp barrier } }
(1) директива critical не может быть использована внутри конструкции single
(2) директива barrier не может быть использована внутри конструкции single
(3) в данном фрагменте программы ошибки нет
Пусть следующая программа скомпилирована компилятором, поддерживающим вложенный параллелизм. #include <stdio.h> #include "omp.h" int counter; int main() { counter=0; omp_set_nested(1); #pragma omp parallel num_threads(2) { if (omp_get_thread_num() == 0) { #pragma omp parallel num_threads(2) { #pragma omp atomic counter++; } } } printf("Counter=%d\n",counter); } Определите значение переменной counter по завершении выполнения этой программы:
(1) 1
(2) 2
(3) 4
Найдите ошибку в следующем фрагменте программы: #define N 10 int A[N], sum; #pragma omp parallel default(shared) num_threads(10) { int iam=omp_get_thread_num(); #pragma omp critical (update_a) #pragma omp critical (update_a) sum +=A[iam]; }
(1) критические секции не могут быть вложены друг в друга
(2) дедлок - взаимная блокировка нитей, возникающая в результате того что одноименные критические секции вложены друг в друга
(3) в данном фрагменте программы ошибки нет
Выберите наиболее походящую оптимизацию, которая позволит сократить время выполнения следующего фрагмента программы: #define N 100 omp_set_num_threads (4); #pragma omp parallel shared(a,b,c,x,y,z) { #pragma omp for for (int i=0; i<N; i++) { z[i] = x[i] + y[i]; } #pragma omp for for (int i=0; i<N; i++) { a[i] = b[i] + c[i]; } }
(1) для циклов, выполнение витков которых распределяется между нитями при помощи директивы for, добавить клаузу schedule(static,25)
(2) для циклов, выполнение витков которых распределяется между нитями при помощи директивы for, добавить клаузу schedule(dynamic)
(3) для циклов, выполнение витков которых распределяется между нитями при помощи директивы for, добавить клаузу nowait
Найдите ошибку в следующем фрагменте MPI/OpenMP-программы, вычисляющей число Пи: #include <mpi.h> #include <omp.h> #define num_steps 100000 void main (int argc, char *argv[]) { int numprocs, myid, mysteps; double pi, step, sum = 0.0 ; MPI_Init(&argc, &argv) ; MPI_Comm_Rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_Size(MPI_COMM_WORLD, &numprocs) ; step = 1.0/(double) num_steps ; mysteps = num_steps/numprocs ; #pragma omp parallel shared(myid, mysteps, step) reduction(+:sum) { #pragma omp for for (int i=myid*mysteps; i<(myid+1)*mysteps ; i++){ double x = (i+0.5)*step; sum += 4.0*step/(1.0+x*x); } MPI_Reduce(&sum, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); } MPI_Finalize(); }
(1) функции MPI_Init, MPI_Comm_Rank, MPI_Comm_Size должны вызываться из параллельной области
(2) до завершения выполнения редукционного OpenMP-оператора выполняется вызов функции MPI_Reduce
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: #define N 10 int icount; #pragma omp threadprivate(icount) #pragma omp parallel { #pragma omp for for (icount=0; icount<N; icount++) { … } }
(1) только статические переменные могут быть указаны в директиве threadprivate (static int icount)
(2) в качестве индексной переменной цикла, распределяемого между нитями при помощи директивы for, не могут использоваться переменные, указанные в директиве threadprivate
(3) в данном фрагменте программы ошибки нет
Рассмотрим фрагмент OpenMP-программы: #include <omp.h> int main (void) { omp_set_nested(0); omp_set_max_active_levels(8); omp_set_num_threads(2); #pragma omp parallel { omp_set_num_threads(2); #pragma omp parallel { /*вложенная параллельная область*/ … } } } Для выполнения вложенной параллельной области будет создана группа нитей, состоящая из:
(1) 1-ой нити
(2) 2-х нитей
(3) нескольких нитей (количество создаваемых нитей зависит от переменной окружения OMP_NUM_THREADS)
Способ распределения витков цикла между нитями группы задается при помощи клаузы schedule(<алгоритм планирования>[,<число итераций>]). Найдите ошибку в следующем фрагменте программы: #pragma omp parallel default(shared) { int i; #pragma omp for schedule(dynamic, omp_get_thread_num()) for (i=0; i<n; i++) { work(i); } }
(1) при динамическом планировании, задаваемом клаузой schedule(dynamic), параметр <число итераций> задать нельзя
(2) значение параметра <число итераций> клаузы schedule отличается для каждой нити группы
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: #include <math.h> double x=1024.0; int n=1024; #pragma omp parallel { #pragma omp atomic x=sqrt(x); #pragma omp atomic n&=0177; }
(1) оператор & (побитовое И) не может быть использован в конструкции atomic
(2) оператор вида x=sqrt(x) не может быть использован в конструкции atomic
(3) в данном фрагменте программы ошибки нет
Определите значение переменной team_size по завершении выполнения следующей программы: #include <stdio.h> #include "omp.h" int main() { int team_size; team_size=0; #pragma omp parallel num_threads(2) { if (omp_get_thread_num() == 0) { team_size=omp_get_team_size(omp_get_level ()); } } printf("Team Size=%d\n",team_size); }
(1) 0
(2) 1
(3) 2
Поиск ошибок в OpenMP-программе, выполняемый Sun Thread Analyzer, основан на:
(1) методе динамического анализа корректности программы
(2) методе статического анализа кода программы
(3) методе сравнительной отладки нескольких запусков одной программы
Выберите наиболее походящую оптимизацию, которая позволит сократить время выполнения следующего фрагмента программы: #include <omp.h> #include <unistd.h> #define msec 1000 int main (void){ omp_set_num_threads (8); #pragma omp parallel for for (int i=0; i<5; i++) for (int j=0; j<5; j++) sleep (msec); }
(1) добавить к директиве parallel for клаузу schedule(static,1)
(2) добавить к директиве parallel for клаузу schedule(dynamic)
(3) добавить к директиве parallel for клаузу collapse(2)
Найдите ошибку в следующем фрагменте MPI/OpenMP-программы, реализующей метод релаксации Якоби: int jacobi(int p, int id, int my_rows, double **u, double **w) { double diff, global_diff, tdiff; int i,j,it; MPI_Status status; it=0; for(;;) { if (id>0) MPI_Send (u[1], N, MPI_DOUBLE, id-1, 0, MPI_COMM_WORLD); if (id<p-1) { MPI_Send (u[my_rows-2], N, MPI_DOUBLE, id+1, 0, MPI_COMM_WORLD); MPI_Recv (u[my_rows-1], N, MPI_DOUBLE, id+1, 0, MPI_COMM_WORLD, &status); } if (id>0) MPI_Recv (u[0], N, MPI_DOUBLE, id-1, 0, MPI_COMM_WORLD, &status); diff=0.0; #pragma omp parallel private (i,j,tdiff) { tdiff=0.0; #pragma omp for for (i=1; i<my_rows; i++) for (j=1; j<N-1; j++) { w[i][j]=(u[i-1][j]+u[i+1][j]+u[i][j-1]+u[i][j+1])/4.0; if (fabs(w[i][j]-u[i][j]) >tdiff) tdiff=fabs(w[i][j]-u[i][j]); } #pragma omp for nowait for (i=1; i<my_rows; i++) for (j=1; j<N-1; j++) u[i][j]=w[i][j]; #pragma omp critical if (tdiff > diff) diff=tdiff; MPI_Allreduce (&diff, &global_diff, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); } if (global_diff <= EPSILON) break; it++; } return it; }
(1) не определен класс для переменных u, w, my_rows, diff, global_diff, используемых в параллельной области -shared(u,w,my_rows,diff,global_diff)
(2) обращения к функции MPI_Allreduce в параллельной области должны выполняться одной нитью (например, внутри конструкции single)
(3) в данном фрагменте программы ошибки нет
Причинная модель консистентности памяти определяется следующим условием:
(1) все процессы наблюдают все обращения к ячейкам памяти в одном и том же порядке. Обращения не упорядочены по времени
(2) все процессы наблюдают все обращения к ячейкам памяти, связанные причинно-следственной связью в одном и том же порядке
(3) все процессы наблюдают операции записи любого процесса в порядке их выполнения. Операции записи различных процессов могут наблюдаться разными процессами в разном порядке
Исполняемыми директивами в OpenMP являются:
(1) barrier
(2) taskwait
(3) threadprivate
Найдите ошибку в следующем фрагменте программы: #pragma omp parallel default(shared) { int i, j; #pragma omp for for (i=0; i<n; i++) { #pragma omp parallel private (i,n) { #pragma omp for for (j=0; j<n; j++) work(i, j); } } }
(1) используются конструкции распределения работ, которые вложены одна в другую
(2) в результате использования клаузы private, значение переменных i и n во вложенном параллельном цикле не определено
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: #define N 10 int A[N],B[N]; #pragma omp parallel default(shared) { int i; ..…#pragma omp master for (i=0; i<N; i++) { A[i]=0; } #pragma omp single B[N-1]=A[N-1]; }
(1) оператор for не может быть использован внутри конструкции master
(2) по завершении конструкции master отсутствует директива barrier
(3) в данном фрагменте программы ошибки нет
Определите способ распределения витков цикла между нитями для следующего фрагмента программы: #define N 100 #include "omp.h" void work(int i); int main () { #pragma omp parallel { omp_set_schedule (omp_sched_static); #pragma omp for schedule(dynamic) for (int i=0;i<N;i++) work (i); } }
(1) статический (static)
(2) динамический (dynamic)
(3) зависит от значения переменной окружения OMP_SCHEDULE
Найдите ошибку в следующем фрагменте программы: #define N 1000 int main (void){ float a[N], tmp; #pragma omp parallel { int i; #pragma omp for private(i) for(i=0; i<N;i++) { tmp= a[i]*a[i]; a[i]=1-tmp; } } }
(1) в директиве parallel отсутствует клауза shared(a)
(2) в директиве for отсутствует клауза private(tmp)
(3) в данном фрагменте программы ошибки нет
Выберите наилучшую стратегию распределения витков цикла между нитями, которая для следующего фрагмента программы даст минимальное время выполнения: #include <omp.h> #include<stdio.h> #include<stdlib.h> #include <time.h> #define msec 1000 int main (void){ srand (time(NULL)); omp_set_num_threads (8); #pragma omp parallel { #pragma omp for schedule (runtime) for(int i=0; i<100;i++) { sleep (rand()*msec); } } }
(1) export OMP_SCHEDULE=”static”
(2) export OMP_SCHEDULE=”dynamic”
(3) export OMP_SCHEDULE=”guided”
Переменные, которые разделяются нитями, и доступ к которым обрабатывается в технологии Intel Cluster OpenMP механизмом DSM, могут быть заданы при помощи:
(1) клаузы SHARED
(2) директивы SHARABLE
(3) опции компилятора
Слабая модель консистентности памяти определяется следующим условием:
(1) совместно используемые данные могут считаться консистентными только после операции синхронизации;
(2) совместно используемые данные могут считаться консистентными после выхода из критической области
(3) совместно используемые данные, относящиеся к данной критической области, становятся консистентными при входе в эту область
Функция omp_get_thread_num возвращает:
(1) уникальный идентификатор нити
(2) номер нити в группе
(3) количество нитей в текущей параллельной области
Найдите ошибку в следующем фрагменте программы: int i, j; #pragma omp parallel default(shared) { #pragma omp for collapse (2) for (i=0; i<n; i++) { for (j=0; j < i; j++) work(i, j); } }
(1) в результате использования клаузы default(shared), счетчики циклов - переменные i и j являются общими для всех нитей
(2) граница вложенного цикла зависит от индексной переменной внешнего цикла (клауза collapsе может быть использована только распределения витков циклов с прямоугольным индексным пространством)
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: #define N 10 int A[N],B[N]; #pragma omp parallel default(shared) num_threads(10) { int iam=omp_get_thread_num(); int tmp; tmp=A[iam]; B[iam]=tmp; }
(1) изменение общей переменной B[iam] выполняется без какой-либо синхронизации
(2) чтение/изменение переменной tmp выполняется без какой-либо синхронизации
(3) в данном фрагменте программы ошибки нет
Определите способ распределения витков цикла между нитями для следующего фрагмента программы: #define N 100 #include "omp.h" void work(int i); int main () { #pragma omp parallel { omp_set_schedule (omp_sched_guided); #pragma omp for for (int i=0;i<N;i++) work (i); } }
(1) управляемый(guided)
(2) зависит от реализации компилятора
(3) зависит от значения переменной окружения OMP_SCHEDULE
Найдите ошибку в следующем фрагменте программы: int main (void){ int a; #pragma omp parallel private(a) { #pragma omp single a = 0; #pragma omp for reduction(+:a) for (int i = 0; i < 10; i++) { a += i; } } }
(1) перед директивой for отсутствует директива barrier
(2) в директиве parallel клауза private (a) должна быть заменена на shared(a)
(3) в данном фрагменте программы ошибки нет
Выберите наилучшую стратегию распределения витков цикла между нитями, которая для следующего фрагмента программы даст минимальное время выполнения: #include <omp.h> #include <unistd.h> #define msec 1000 int main (void){ omp_set_num_threads (4); #pragma omp parallel { #pragma omp for schedule (runtime) for(int i=0; i<60;i++) { sleep (msec); } } }
(1) export OMP_SCHEDULE=”static,10”
(2) export OMP_SCHEDULE=”dynamic,15”
(3) export OMP_SCHEDULE=”static,20”
Реализация технологии Intel Cluster OpenMP стала возможной, поскольку в OpenMP используется:
(1) последовательная модель консистентности памяти (все нити наблюдают все обращения к ячейкам памяти в одном и том же порядке. Обращения не упорядочены по времени)
(2) причинная модель консистентности памяти (все нити наблюдают все обращения к ячейкам памяти, связанные причинно-следственной связью в одном и том же порядке)
(3) слабая модель консистентности памяти (совместно используемые данные становятся консистентными после операции синхронизации)
Пусть W(x)a – операция записи в переменную x значения a. Пусть R(x)a – операция чтения переменной x, где a – прочитанное значение переменной x. Следующая последовательность событий:
P1: W(x)aW(x)c
P2:R(x)aW(x)b
P3:R(x)aR(x)cR(x)b
P4:R(x)aR(x)bR(x)c
(1) допустима при строгой модели консистентности
(2) допустима при причинной модели консистентности
(3) допустима при последовательной модели консистентности
При реализации компилятором редукционного оператора, описанного при помощи клаузы reduction (-: sub), где переменная sub имеет тип integer, для каждой нити создается локальная копия переменной sub, начальное значение которой будет инициализировано:
(1) -MAXINT (минимально возможное целое число)
(2) 0
(3) MAXINT (максимально возможное целое число)
Найдите ошибку в следующем фрагменте программы: #define N 10 int i; #pragma omp parallel { #pragma omp for private(i) lastprivate(i) for (i=0; i<N; i++) { … } #pragma omp single printf (“Number of iteration=%d\n”, i); }
(1) одна и та же переменная не может быть указана в клаузах private и lastprivate одновременно
(2) индексная переменная цикла, витки которого распределяются между нитями при помощи директивы for, не может быть указана в клаузе lastprivate
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: #define N 10 int A[N], sum; #pragma omp parallel default(shared) num_threads(10) { int iam=omp_get_thread_num(); #pragma omp critical (update_a) #pragma omp critical (update_a) sum +=A[iam]; }
(1) критические секции не могут быть вложены друг в друга
(2) одноименные критические секции не могут быть вложены друг в друга
(3) в данном фрагменте программы ошибки нет
Определите количество нитей, между которыми будет распределена работа в параллельной области: #include "omp.h" void work(int i); int main () { int n; n=10; #pragma omp parallel num_threads(4) if (n>20) { #pragma omp for for (int i=0;i<n;i++) work (i); } }
(1) зависит от значения переменных окружения OMP_THREAD_LIMIT и OMP_NUM_THREADS
(2) 1
(3) 4
Найдите ошибку в следующем фрагменте программы: #define N 1000 float a[N], b[N]; int main (void){ int i; #pragma omp parallel { #pragma omp for for (i=0; i<N-1; i++) { a[i] = b[i] + b[i+1]; } a[i]=b[i]; } }
(1) в директиве parallel отсутствует клауза shared(a,b)
(2) в директиве parallel отсутствует клауза private(i)
(3) в директиве for отсутствует клауза lastpivate(i)
Выберите наиболее походящую оптимизацию, которая позволит сократить время выполнения следующего фрагмента программы: #include <omp.h> #include <stdio.h> #define N 100 int c[N]; int val= 1; int main (void) { omp_set_num_threads (8); #pragma omp parallel shared(val, c) { #pragma omp for for (int i=0; i<N; i++) { #pragma omp critical val = val && (c[i]<100); } } printf (“Result=%4.2f\n”, val); }
(1) вместо директивы critical использовать механизм семафоров (omp_set_lock/omp_unset_lock)
(2) заменить директиву critical на директиву critical (<имя_критической_секции>)
(3) добавить к директиве for клаузу reduction(&&:val) и убрать директиву critical
При использовании гибридной модели параллельного программирования DVM/OpenMP:
(1) все нити, выполняемые на различных узлах кластера, взаимодействуют друг с другом через общую память
(2) все нити, выполняемые на узле кластера, взаимодействуют через общую память, а для обмена информацией между узлами кластера используются механизмы, предоставляемые DVM-системой
(3) все нити взаимодействуют друг с другом при помощи механизмов, предоставляемых DVM-системой
Найдите ошибку в следующем фрагменте программы: int i=0; int numt = omp_get_max_threads(); #pragma omp parallel default (none) private (i) { #pragma omp for for(i=0; i< numt; i++) Work(i); }
(1) не описан класс для переменной numt. Необходимо добавить спецификацию shared(numt)
(2) не описан класс для переменной numt. Необходимо добавить спецификацию private(numt)
(3) в данном фрагменте программы ошибки нет
Пусть перед входом в параллельную область вызывается функция omp_set_num_threads. Пусть в директиве создания этой параллельной области указана клауза num_threads. Количество создаваемых нитей будет:
(1) определяться клаузой num_threads
(2) определяться вызовом функции omp_set_num_threads
(3) зависеть от реализации компилятора
Найдите ошибку в следующем фрагменте программы: #pragma omp parallel default(shared) { int i; #pragma omp for schedule(dynamic) for (i=0; i<n; i++) { #pragma omp ordered printf("iteration %d\n", i); } }
(1) использование клаузы schedule(dynamic) для цикла for, в котором используется директива ordered запрещено
(2) в директиве for отсутствует клауза ordered
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: int x=0; omp_lock_t lcka, lckb; omp_init_lock (&lcka); omp_init_lock (&lckb); #pragma omp parallel { int iam=omp_get_thread_num(); if (iam ==0) { omp_set_lock (&lcka); omp_set_lock (&lckb); x = x + 1; omp_unset_lock (&lckb); omp_unset_lock (&lcka); } else { omp_set_lock (&lckb); omp_set_lock (&lcka); x = x + 2; omp_unset_lock (&lcka); omp_unset_lock (&lckb); } } } omp_destroy_lock (&lcka); omp_destroy_lock (&lckb);
(1) после установки блокировки в результате вызова функции omp_set_lock(&lcka), повторное обращение нитью к функции omp_set_lock(&lckb) некорректно (повторное обращение omp_set_lock(&lckb) должно быть заменено на omp_set_nest_lock(&lckb))
(2) дедлок - взаимная блокировка нитей, возникающая, в случае если master-нить, выполнила omp_set_lock (&lcka), а другая нить выполнила omp_set_lock (&lckb)
(3) в данном фрагменте программы ошибки нет
Определите значение переменной team_size по завершении выполнения следующей программы: #include <stdio.h> #include "omp.h" int main() { int team_size; team_size=0; #pragma omp parallel num_threads(2) { if (omp_get_thread_num() == 0) { team_size=omp_get_team_size(0); } } printf("Team Size=%d\n",team_size); }
(1) 0
(2) 1
(3) 2
Intel Thread Checker:
(1) обнаруживает все возможные ошибки типа datarace и deadlock в программе
(2) ошибки, которые проявились при выполнении программы на заданном наборе входных тестовых данных
Выберите наиболее походящую оптимизацию, которая позволит сократить время выполнения следующего фрагмента программы: #include <omp.h> #include <unistd.h> #define msec 1000 int main (void){ omp_set_num_threads (8); for (int i=0; i<80; i++) #pragma omp parallel for for (int j=0; j<80; j++) sleep (msec); }
(1) добавить к директиве parallel for клаузу schedule(dynamic)
(2) добавить к директиве parallel for клаузу schedule(static,10)
(3) переставить директиву parallel for (распределить между нитями выполнение витков цикла по i)
Найдите ошибку в следующем фрагменте MPI/OpenMP-программы, реализующей метод релаксации Якоби: int jacobi(int p, int id, int my_rows, double **u, double **w) { double diff, global_diff, tdiff; int i,j,it; MPI_Status status; it=0; #pragma omp parallel private (i,j,tdiff) { for(;;) { #pragma omp master { diff=0.0; if (id>0) MPI_Send (u[1], N, MPI_DOUBLE, id-1, 0, MPI_COMM_WORLD); if (id<p-1) { MPI_Send (u[my_rows-2], N, MPI_DOUBLE, id+1, 0, MPI_COMM_WORLD); MPI_Recv (u[my_rows-1], N, MPI_DOUBLE, id+1, 0, MPI_COMM_WORLD, &status); } if (id>0) MPI_Recv (u[0], N, MPI_DOUBLE, id-1, 0, MPI_COMM_WORLD, &status); } /*end of master*/ tdiff=0.0; #pragma omp for for (i=1; i<my_rows; i++) for (j=1; j<N-1; j++) { w[i][j]=(u[i-1][j]+u[i+1][j]+u[i][j-1]+u[i][j+1])/4.0; if (fabs(w[i][j]-u[i][j]) >tdiff) tdiff=fabs(w[i][j]-u[i][j]); } #pragma omp for nowait for (i=1; i<my_rows; i++) for (j=1; j<N-1; j++) u[i][j]=w[i][j]; #pragma omp critical if (tdiff > diff) diff=tdiff; #pragma omp barrier #pragma omp single { it++; MPI_Allreduce (&diff, &global_diff, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); } /*end of single*/ if (global_diff <= EPSILON) break; } return it; }
(1) не определен класс для переменных my_rows, diff, id, p, status, u, w, it, global_diff, используемых в параллельной области -shared(my_rows,diff,diff,id,p,status,u,w,it,global_diff)
(2) отсутствует барьерная синхронизация нитей (директива barrier) по завершении конструкции master
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: #define N 10 int i; #pragma omp parallel firstprivate(i) lastprivate(i) { for (i=0; i<N; i++) { … } }
(1) одна и та же переменная не может быть указана в клаузах firstprivate и lastprivate одновременно
(2) клауза lastprivate не может использоваться в директиве parallel
(3) клауза firstprivate не может использоваться в директиве parallel
Найдите ошибку в следующем фрагменте программы: #pragma omp parallel default(shared) { int i; #pragma omp for lastprivate(i) for (i=0; i<n + omp_get_thread_num (); i++) { work(i); } }
(1) индексная переменная цикла, витки которого распределяются между нитями при помощи директивы for, не может быть указана в клаузе lastprivate
(2) значения выражений, указанных в заголовке цикла for, отличаются для каждой нити группы
(3) в данном фрагменте программы ошибки нет
Найдите ошибку в следующем фрагменте программы: int numt=0; #pragma omp parallel { #pragma omp critical { numt=omp_get_num_threads(); #pragma omp barrier #pragma omp flush (numt) } }
(1) директива barrier не может быть использована внутри критической секции (конструкции critical)
(2) директива flush не может быть использована внутри критической секции (конструкции critical)
(3) в данном фрагменте программы ошибки нет
Пусть следующая программа скомпилирована компилятором, поддерживающим вложенный параллелизм. #include <stdio.h> #include "omp.h" int counter; int main() { counter=0; omp_set_nested(0); #pragma omp parallel num_threads(2) { #pragma omp parallel num_threads(2) { #pragma omp atomic counter++; } } printf("Counter=%d\n",counter); } Определите значение переменной counter по завершении выполнения этой программы:
(1) 1
(2) 2
(3) 4
#define N 10 int A[N],B[N], sum; #pragma omp parallel default(shared) num_threads(10) { int iam=omp_get_thread_num(); if (iam ==0) { #pragma omp critical (update_a) #pragma omp critical (update_b) sum +=A[iam]; } else { #pragma omp critical (update_b) #pragma omp critical (update_a) sum +=B[iam]; } }
(1) критические секции, определяемые директивой critical, не могут быть вложены друг в друга
(2) дедлок - взаимная блокировка нитей, возникающая при входе master-нитью в критическую секцию с именем update_a и любой другой нитью в секцию с именем update_b (в этом случае вложенные критические секции не смогут быть обработаны)
(3) в данном фрагменте программы ошибки нет
Выберите наиболее походящую оптимизацию, которая позволит сократить время выполнения следующего фрагмента программы: #define N 80 omp_set_num_threads (8); #pragma omp parallel shared(a,b,c,x,y,z) { #pragma omp for for (int i=0; i<N; i++) { z[i] = x[i] + y[i]; } #pragma omp for for (int i=0; i<N; i++) { a[i] = b[i] + c[i]; } }
(1) для циклов, выполнение витков которых распределяется между нитями при помощи директивы for, добавить клаузу schedule(static,10)
(2) для циклов, выполнение витков которых распределяется между нитями при помощи директивы for, добавить клаузу schedule(dynamic)
(3) для первого цикла, выполнение витков которого распределяется между нитями при помощи директивы for, добавить клаузу nowait
Найдите ошибку в следующем фрагменте MPI/OpenMP-программы, вычисляющей число Пи: #include <mpi.h> #include <omp.h> #define num_steps 100000 void main (int argc, char *argv[]) { int numprocs, myid, mysteps; double pi, step, sum = 0.0 ; MPI_Init(&argc, &argv) ; MPI_Comm_Rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_Size(MPI_COMM_WORLD, &numprocs) ; step = 1.0/(double) num_steps ; mysteps = num_steps/numprocs ; #pragma omp parallel shared(myid, mysteps, step) { #pragma omp for reduction(+:sum) for (int i=myid*mysteps; i<(myid+1)*mysteps ; i++){ double x = (i+0.5)*step; sum += 4.0 /(1.0+x*x); } sum *= step ; } MPI_Reduce(&sum, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); MPI_Finalize(); }
(1) функции MPI_Init, MPI_Comm_Rank, MPI_Comm_Size и MPI_Reduce должны вызываться из параллельной области
(2) конфликт доступа к данным (race condition), возникающий в результате выполнения оператора sum *= step в параллельной области
(3) в данном фрагменте программы ошибки нет