Параллельное программирование в стандарте OpenMP

Содержание

Слайд 2

Содержание

Модель программирования в общей памяти
Модель FORK-JOIN
Стандарт OpenMP
Основные понятия и функции OpenMP

Содержание Модель программирования в общей памяти Модель FORK-JOIN Стандарт OpenMP Основные понятия и функции OpenMP

Слайд 3

Программирование в общей памяти


Процесс 0

Процесс 1

Процесс N-1

Данные

Параллельное приложение состоит из нескольких процессов,

Программирование в общей памяти … Процесс 0 Процесс 1 Процесс N-1 Данные
выполняющихся одновременно.
Процессы разделяют общую память.
Обмены между процессами осуществляются посредством чтения/записи данных в общей памяти.
Процессы могут выполняться как на одном и том же, так и на разных процессорах.

Слайд 4

Модель FORK-JOIN

Современные операционные системы поддерживают полновесные процессы (программы) и легковесные процессы (нити).
Процесс

Модель FORK-JOIN Современные операционные системы поддерживают полновесные процессы (программы) и легковесные процессы
– главная нить.
Нить может запускать другие нити в рамках процесса. Каждая нить имеет собственный сегмент стека.
Все нити процесса разделяют сегмент данных процесса.

Сегмент данных

Главная нить (процесс)
main()


нить

Сег. стека

Сегмент стека

нить

Сег. стека

Нить

Нить


Fork

Join

Слайд 5

Стандарт OpenMP

OpenMP – стандарт, реализующий модели программирования в общей памяти и Fork-Join.
Стандарт

Стандарт OpenMP OpenMP – стандарт, реализующий модели программирования в общей памяти и
представляет собой набор директив компилятора и спецификаций подпрограмм для на языках C, С++ и FORTRAN.
Стандарт реализуется разработчиками компиляторов для различных аппаратно-программных платформ (кластеры, персональные компьютеры, …, Windows, Unix/Linux, …).

Слайд 6

Структура OpenMP-программы

Параллельные регионы

Главная нить

Главная нить (программа) порождает семейство дочерних нитей (сколько необходимо).

Структура OpenMP-программы Параллельные регионы Главная нить Главная нить (программа) порождает семейство дочерних
Порождение и завершение осуществляется с помощью директив компилятора.
Преобразование последовательной программы в параллельную может происходить "инкрементно".

Нити

Последовательные регионы

Слайд 7

Директивы OpenMP

Директивы OpenMP – директивы C/C++ компилятора #pragma.
Для использования директив необходимо установить

Директивы OpenMP Директивы OpenMP – директивы C/C++ компилятора #pragma. Для использования директив
соответствующие параметры компилятора (обычно -openmp).
Синтаксис директив OpenMP: #pragma omp имя_директивы [параметры]
Примеры: #pragma omp parallel #pragma omp for private(i, j) reduction(+: sum)

Слайд 8

Функции библиотеки OpenMP

Назначение функций библиотеки:
контроль и просмотр параметров OpenMP-программы
omp_get_thread_num() возвращает номер текущей

Функции библиотеки OpenMP Назначение функций библиотеки: контроль и просмотр параметров OpenMP-программы omp_get_thread_num()
нити
явная синхронизация нитей на базе "замков"
omp_set_lock() устанавливает "замок"
Для использования функций необходимо подключить библиотеку
#include "omp.h"

Слайд 9

Переменные окружения OpenMP

Переменные окружения контролируют поведение приложения.
OMP_NUM_THREADS – количество нитей в параллельном

Переменные окружения OpenMP Переменные окружения контролируют поведение приложения. OMP_NUM_THREADS – количество нитей
регионе
OMP_DYNAMIC – разрешение или запрет динамического изменения количества нитей.
OMP_NESTED – разрешение или запрет вложенных параллельных регионов.
OMP_SCHEDULE – способ распределения итераций в цикле.
Функции назначения параметров изменяют значения соответствующих переменных окружения.

Слайд 10

Директивы определения параллельных фрагментов

#pragma omp parallel Определяет блок кода, который будет выполнен

Директивы определения параллельных фрагментов #pragma omp parallel Определяет блок кода, который будет
всеми созданными на входе в этот блок нитями.
#pragma omp for Определяет цикл, итерации которого должны выполняться одновременно несколькими нитями.
#pragma omp section Определяет множество блоков кода, каждый из который будет выполняться только одной из созданных на входе в этот блок нитью.
#pragma omp master Определяет блок кода, который будет выполнен только главной нитью.

Слайд 11

Простая программа на OpenMP

void main() { printf("Hello!\n"); }

void main() { #pragma omp parallel {
printf("Hello!\n"); } }

Результат

Результат (для 2-х

Простая программа на OpenMP void main() { printf("Hello!\n"); } void main() {
нитей)

Hello!

Hello! Hello!

Последовательный код

Параллельный код

Слайд 12

Директива parallel for

OpenMP поддерживает редукцию вычислительных операций, выполняемых в циклах. Редукция

Директива parallel for OpenMP поддерживает редукцию вычислительных операций, выполняемых в циклах. Редукция
подразумевает определение для каждой нити частной переменной для вычисления "частичного" результата и автоматическое выполнение операции "слияния" частичных результатов.

#pragma omp parallel for reduction(+:sum)
for (i=0; i sum += a[i] * b[i];
}

Слайд 13

Параллельные секции

Явное определение блоков кода, которые могут исполняться параллельно.

Послед.

Паралл.

#pragma omp parallel sections
{

Параллельные секции Явное определение блоков кода, которые могут исполняться параллельно. Послед. Паралл.
#pragma omp section
phase1();
#pragma omp section
phase2();
#pragma omp section
phase3();
}

Слайд 14

Область видимости переменных

Общая переменная (shared) – доступна для модификации всем нитям.
Частная переменная

Область видимости переменных Общая переменная (shared) – доступна для модификации всем нитям.
(private) – доступна для модификации только одной (создавшей ее) нити только на время выполнения этой нити.
Правила видимости переменных:
все переменные, определенные вне параллельной области – общие;
все переменные, определенные внутри параллельной области – частные.

Слайд 15

Общие и частные переменные

void main() {
int a, b, c;

#pragma omp

Общие и частные переменные void main() { int a, b, c; …
parallel
{
int d, e;

}
}

Общие

Частные

Слайд 16

Явное указание области видимости

Для явного указания области видимости используются следующие параметры директив:
shared()

Явное указание области видимости Для явного указания области видимости используются следующие параметры
– общие переменные
private() – частные переменные
Примеры:
#pragma omp parallel shared(buf)
#pragma omp for private(i, j)

Слайд 17

void main() {
int a, b, c;

#pragma omp parallel shared(a) private(b)

void main() { int a, b, c; … #pragma omp parallel shared(a)
{
int d, e;

}
}

Общие и частные переменные

Общие

Частные

Общие

Частные

Слайд 18

void main() {
int rank;
#pragma omp parallel
{
rank = omp_get_thread_num();
}

void main() { int rank; #pragma omp parallel { rank = omp_get_thread_num();
printf("%d\n", rank);
}

Общие и частные переменные

void main() {
int rank;
#pragma omp parallel
{
rank = omp_get_thread_num();
printf("%d\n", rank);
}
}

Слайд 19

void main() {
int rank;
#pragma omp parallel shared (rank)
{
rank = omp_get_thread_num();

void main() { int rank; #pragma omp parallel shared (rank) { rank
printf("%d\n", rank);
}
}

Общие и частные переменные

void main() {
int rank;
#pragma omp parallel private (rank)
{
rank = omp_get_thread_num();
printf("%d\n", rank);
}
}

Слайд 20

Директивы синхронизации

#pragma omp master Определяет блок кода, который будет выполнен только главной

Директивы синхронизации #pragma omp master Определяет блок кода, который будет выполнен только
нитью.
#pragma omp critical Определяет блок кода, который не должен выполняться одновременно двумя или более нитями.
#pragma omp barrier Определяет точку барьерной синхронизации, в которой каждая нить дожидается всех остальных.
#pragma omp atomic Определяет переменную в левой части оператора "атомарного" присваивания, которая должна корректно обновляться несколькими нитями.
#pragma omp flush Явно определяет точку, в которой обеспечивается одинаковый вид памяти для всех нитей.

Слайд 21

#pragma omp master

Определяет блок кода, который будет выполнен только главной нитью. Не

#pragma omp master Определяет блок кода, который будет выполнен только главной нитью.
подразумевает барьера для других нитей.

#pragma omp parallel
{
DoSomeJob1(omp_get_thread_num());
#pragma master
{
printf("Job #1 done\n");
}
DoSomeJob2(omp_get_thread_num());
#pragma master
{
printf("Job #2 done\n");
}
}