Параллельное программирование с использованием технологии OpenMP Аксёнов Сергей Владимирович к.т.н., доцент каф.ОСУ ТПУ Лекция 3 Томский политехнический университет
Параллельные секции Директива sections определяет набор независимых секций кода, каждая из которых выполняется своей нитью. Директива section задаёт участок кода внутри секции sections для выполнения одной нитью. Параллельное программирование с использованием технологии OpenMP Аксёнов С.В. 2 int num; omp_set_num_threads(3); #pragma omp parallel private(num) { num=omp_get_thread_num(); #pragma omp sections { #pragma omp section //Не является обязательной cout
Опция lastprivate() В опции lastprivate(список) определяются переменные, перечисленные в списке, которым присваивается результат, полученный в последней секции. Параллельное программирование с использованием технологии OpenMP Аксёнов С.В. 3 int num, n; omp_set_num_threads(2); #pragma omp parallel private(num) { num=omp_get_thread_num(); #pragma omp sections lastprivate(n) { #pragma omp section //Не является обязательной { n = 1; cout
Барьер Нити, выполняющие текущую параллельную область, дойдя до директивы barrier, останавливаются и ждут, пока все нити не дойдут до этой точки программы, после чего они разблокируются и продолжают работать дальше. Параллельное программирование с использованием технологии OpenMP Аксёнов С.В. 4 int num; int n=0; omp_set_num_threads(3); #pragma omp parallel private(num) { num=omp_get_thread_num(); cout
Директива ordered Директива ordered определяет блок внутри тела цикла, который должен выполняться в том порядке, в котором итерации идут в последовательном цикле. В параллельном цикле должна быть задана опция ordered. Нить, выполняющая первую итерацию цикла, выполняет операции данного блока. Нить, выполняющая любую следующую итерацию, должна сначала дождаться выполнения всех операций блока всеми нитями, выполняющими предыдущие итерации. Параллельное программирование с использованием технологии OpenMP Аксёнов С.В. 5
Директива ordered: пример Параллельное программирование с использованием технологии OpenMP Аксёнов С.В. 6 int i, n; omp_set_num_threads(4); #pragma omp parallel private (i, n) { n=omp_get_thread_num(); #pragma omp for ordered for (i=0; i
Критические секции: critical Директива critical оформляет критическую секцию программы. В каждый момент времени в критической секции может находиться не более одной нити. Если критическая секция уже выполняется какой-либо нитью, то все другие нити, выполнившие директиву для секции с данным именем, будут заблокированы, пока вошедшая нить не закончит выполнение данной критической секции. Как только работавшая нить выйдет из критической секции, одна из заблокированных на входе нитей войдет в неё. Если на входе в критическую секцию стояло несколько нитей, то случайным образом выбирается одна из них, а остальные заблокированные нити продолжают ожидание. Параллельное программирование с использованием технологии OpenMP Аксёнов С.В. 7
Критические секции: пример Параллельное программирование с использованием технологии OpenMP Аксёнов С.В. 8 int n; omp_set_num_threads(5); #pragma omp parallel { #pragma omp critical { n=omp_get_thread_num(); cout
Директива atomic Директива atomic относится к идущему непосредственно за ней оператору присваивания, гарантируя корректную работу с общей переменной, стоящей в его левой части. На время выполнения оператора блокируется доступ к данной переменной всем запущенным в данный момент нитям, кроме нити, выполняющей операцию. Атомарной является только работа с переменной в левой части оператора присваивания, при этом вычисления в правой части не обязаны быть атомарными. Параллельное программирование с использованием технологии OpenMP Аксёнов С.В. 9
Пример atomic Параллельное программирование с использованием технологии OpenMP Аксёнов С.В. 10 omp_set_num_threads(4); int count = 0; #pragma omp parallel { #pragma omp atomic count++; } cout
Замки Один из вариантов синхронизации в OpenMP реализуется через механизм замков. Замок может находиться в одном из трёх состояний: неинициализированный, разблокированный или заблокированный. Разблокированный замок может быть захвачен некоторой нитью. При этом он переходит в заблокированное состояние. Нить, захватившая замок, и только она может его освободить, после чего замок возвращается в разблокированное состояние. Существует два типа замков: простые замки и множественные замки. Множественный замок может многократно захватываться одной нитью перед его освобождением, в то время как простой замок может быть захвачен только однажды. Параллельное программирование с использованием технологии OpenMP Аксёнов С.В. 11
Функции работы с замками Для инициализации простого или множественного замка используются соответственно функции void omp_init_lock(omp_lock_t *lock); void omp_init_nest_lock(omp_nest_lock_t *lock); Функции omp_destroy_lock() и omp_destroy_nest_lock() используются для переведения простого или множественного замка в неинициализированное состояние. Функции захватывания замка omp_set_lock() и omp_set_nest_lock(). Функции освобождения замка omp_unset_lock() и omp_unset_nest_lock(). Параллельное программирование с использованием технологии OpenMP Аксёнов С.В. 12
Пример использования замков 1 Параллельное программирование с использованием технологии OpenMP Аксёнов С.В. 13 omp_lock_t lock; int n; omp_set_num_threads(3); omp_init_lock(&lock); #pragma omp parallel private (n) { n=omp_get_thread_num(); omp_set_lock(&lock); printf("Начало заблокированной секции, Номер потока %d\n", n); Sleep(5); printf("Конец заблокированной секции, Номер потока %d\n", n); omp_unset_lock(&lock); } omp_destroy_lock(&lock); Выполнение Начало заблокированной секции, Номер потока 2 Конец заблокированной секции, Номер потока 2 Начало заблокированной секции, Номер потока 0 Конец заблокированной секции, Номер потока 0 Начало заблокированной секции, Номер потока 1 Конец заблокированной секции, Номер потока 1
Пример использования замков 2 Параллельное программирование с использованием технологии OpenMP Аксёнов С.В. 14 omp_lock_t lock; int n; omp_set_num_threads(3); omp_init_lock(&lock); #pragma omp parallel private (n) { n=omp_get_thread_num(); while (!omp_test_lock (&lock)) { printf("Секция заблокирована, Номер потока %d\n", n); Sleep(2); } printf("Начало заблокированной секции, Номер потока %d\n", n); Sleep(5); printf("Конец заблокированной секции, Номер потока %d\n", n); omp_unset_lock(&lock); } omp_destroy_lock(&lock); Выполнение Начало ЗС, Номер потока 2 Секция заблок-на, Номер п-ка 0 Секция заблок-на, Номер п-ка 1 Секция заблок-на, Номер п-ка 0 Секция заблок-на, Номер п-ка 1 Секция заблок-на, Номер п-ка 0 Конец ЗС, Номер потока 2 Начало ЗС, Номер потока 0 Секция заблок-на, Номер п-ка 1 Конец ЗС, Номер потока 0 Начало ЗС, Номер потока 1 Конец ЗС, Номер потока 1