Главная /
Программирование /
Параллельное программирование с OpenMP
Параллельное программирование с OpenMP - ответы на тесты Интуит
Правильные ответы выделены зелёным цветом.
Все ответы: В рамках курса проводится изучение основных возможностей стандарта 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)a | W(x)b | S | |||
---|---|---|---|---|---|
P2: | R(x)a | R(x)b | S | ||
P3: | R(x)b | R(x)a | S |
(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) в данном фрагменте программы ошибки нет
Определите класс по умолчанию для переменной
int i=0;
int numt = omp_get_max_threads();
#pragma omp parallel for
for(i=0; i< numt; i++)
Work(i);
numt
:
(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
)
Способ распределения витков цикла между нитями группы задается при помощи клаузы#pragma omp parallel default(shared)
{
int i;
#pragma omp for schedule(static, omp_get_thread_num())
for (i=0; i<n; i++) {
work(i);
}
}
schedule(<алгоритм планирования>[,<число итераций>])
.
Найдите ошибку в следующем фрагменте программы:
(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) в данном фрагменте программы ошибки нет
Определите значение переменной #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);
}
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) зависит от реализации компилятора
(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)a | W(x)b | S | ||
---|---|---|---|---|
P2: | S | R(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
)
Способ распределения витков цикла между нитями группы задается при помощи клаузы #pragma omp parallel default(shared)
{
int i;
#pragma omp for schedule(dynamic, omp_get_thread_num())
for (i=0; i<n; i++) {
work(i);
}
}
schedule(<алгоритм планирования>[,<число итераций>])
.
Найдите ошибку в следующем фрагменте программы:
(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) в данном фрагменте программы ошибки нет
Определите значение переменной #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);
}
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)a | W(x)c | ||||
---|---|---|---|---|---|
P2: | R(x)a | W(x)b | |||
P3: | R(x)a | R(x)c | R(x)b | ||
P4: | R(x)a | R(x)b | R(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) в данном фрагменте программы ошибки нет
Определите значение переменной #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);
}
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
(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) в данном фрагменте программы ошибки нет