Технологія OpenMP для розробки паралельних програм для систем із спільною пам’яттю
OpenMP (Open Multi-Processing) — це набір директив компілятора, бібліотечних процедур та змінних середовища, які призначені для програмування багатопоточних застосунків на багатопроцесорних системах із спільною пам'яттю на мовах C, C++ та Fortran.
Розробку специфікації OpenMP ведуть кілька великих виробників обчислювальної техніки та програмного забезпечення, робота яких регулюється некомерційною організацією, названою OpenMP Architecture Review Board (ARB). Детальна специфікація OpenMP міститься на сторінці. Специфікації для мов Fortran і C/C++ з'явилися відповідно в жовтні 1997 року і жовтні 1998 року.
OpenMP можна розглядати як високорівневу надбудову над Pthreads (або аналогічними бібліотеками потоків). POSIX-інтерфейс для організації потоків Pthreads підтримується широко (практично на всіх UNIX-системах), проте з багатьох причин не підходить для практичного паралельного програмування:
- немає підтримки Fortran
- дуже низький рівень
- немає підтримки паралелізму за даними
- механізм нитей спочатку розроблявся не для цілей організації паралелізму
OpenMP реалізує паралельні обчислення за допомогою багатопотоковості, в якій «головний» (master) потік створює набір підлеглих (slave) потоків і завдання розподіляється між ними. Передбачається, що потоки виконуються паралельно на машині з декількома процесорами (кількість процесорів не обов'язково має бути більше або дорівнювати кількості потоків).
Завдання, що виконуються потоками паралельно, так само як і дані, необхідні для виконання цих завдань, описуються за допомогою спеціальних директив препроцесора відповідної мови — прагм. Наприклад, ділянка коду на мові Fortran, яка повинна виконуватися кількома потоками, кожна з яких має свою копію змінної N, передує наступній !$OMP PARALLEL PRIVATE(N)
Кількість створюваних потоків може регулюватися як самою програмою за допомогою виклику бібліотечних процедур, так і ззовні, за допомогою змінних оточення.
Переваги
- За рахунок ідеї «інкрементального розпаралелювання» OpenMP ідеально підходить для розробників, що прагнуть швидко розпаралелювати свої обчислювальні програми з великими паралельними циклами. Розробник не створює нову паралельну програму, а просто послідовно додає в текст програми OpenMP-директиви.
- При цьому, OpenMP — досить гнучкий механізм, що надає розробникові великі можливості контролю над поведінкою паралельної програми.
- Передбачається, що OpenMP-програма на однопроцесорній платформі може бути використана як послідовна програма, тобто немає необхідності підтримувати послідовну та паралельну версії. Директиви OpenMP просто ігноруються послідовним компілятором, а для виклику процедур OpenMP можуть бути підставлені заглушки (stubs), текст яких приведений в специфікаціях.
- Однією з переваг OpenMP розробники вважають підтримку так званих «orphan» (відірваних) директив, тобто директиви синхронізації і розподілу роботи можуть не входити безпосередньо в лексичний контекст паралельної області.
Ключовими елементами OpenMP є
- конструкції для створення потоків (директива parallel),
- конструкції розподілу роботи між потоками (директиви DO / for та section),
- конструкції для керування роботою з даними (вираз shared і private),
- конструкції для синхронізації потоків (директиви critical atomic і barrier),
- процедури бібліотеки підтримки часу виконанню (наприклад, omp_get_thread_num),
- змінні оточення (наприклад, OMP_NUM_THREADS).
Приклад програми
Нижче наведені приклади програм з використанням директив OpenMP:
У цій програмі два вектора (a і b) додаються паралельно десятьма потоками.
#include <stdio.h>
#include <omp.h>
#define N 100
int main(int argc, char *argv[])
{
float a[N], b[N], c[N];
int i;
omp_set_dynamic(0); // заборонити змінювати число потоків за допомогою змінної оточення
omp_set_num_threads(10); // встановити число потоків у 10
// ініціалізуємо вектори
for (i = 0; i < N; i++) {
a[i] = i * 1.0;
b[i] = i * 2.0;
}
// обчислюємо суму векторів
#pragma omp parallel shared(a, b, c) private(i)
{
#pragma omp for
for (i = 0; i < N; i++)
c[i] = a[i] + b[i];
}
printf ("%f\n", c[10]);
return 0;
}
Існуючі реалізації
OpenMP підтримується багатьма комерційними компіляторами.
Компілятори Oracle Solaris Studio, v12.3, підтримують офіційно специфікацію OpenMP 3.1 — з покращеною продуктивністю під ОС Solaris та обмеженим числом платформ під ОС Linux
Visual C++ 2005 підтримує OpenMP у редакціях Professional і Team System.
GCC 4.2 підтримує OpenMP 2.5, а деякі дистрибутиви (такі як Fedora Core 5 gcc) включили підтримку в свої версії GCC 4.1. Починаючи з GCC 4.4 підтримується стандарт OpenMP 3.0 а з версії GCC 4.7 — OpenMP 3.1
В універсальному комплексі Intel Parallel Studio від Intel об'єднано компілятори C++ та Фортран, бібліотеки оптимізації та паралелізації, включаючи OpenMP 3.1 (починаючи з версії компіляторів 12.1), а також засоби перевірки помилок та продуктивності, зневаджувач і профайлер для останніх поколінь багатоядерних процесорів.
Приклад реалізації
Компілятори Sun Studio створюють окрему процедуру з вихідного коду, розташованого під директивою parallel, а замість самої директиви вставляють виклик процедури __mt_MasterFunction_ бібліотеки libmtsk, передаючи їй адресу штучно створену. Таким чином, розподілювані (shared) дані можуть бути передані останній за посиланням, а власні (private) оголошуються всередині цієї процедури, опиняючись незалежні від своїх копій в інших нитях.
Процедура __mt_MasterFunction_ створює групу нитей (кількістю 9 у наведеному вище прикладі на мові C), які будуть виконувати код конструкції parallel, а нить, що викликала їх, стає головною у групі. Потім головна нить організовує роботу підлеглих нитей, після чого починає виконувати код користувача сама. Коли код буде виконаний, головна нить викликає процедуру _mt_EndOfTask_Barrier_ що синхронізує її з іншими.
Шрифти
Розмір шрифта
Колір тексту
Колір тла
Кернінг шрифтів
Видимість картинок
Інтервал між літерами
Висота рядка
Виділити посилання
Вирівнювання тексту
Ширина абзацу