Обрамні функції

Існує кілька функцій, які використовуються в будь-якому, навіть найкоротшому додатку MPI. Займаються вони не так власне передачею даних, як її забезпеченням:

Ініціалізація бібліотеки. Одна з перших інструкцій у функції main (головної функції програми):

Аварійне закриття бібліотеки. Викликається, якщо програма користувача завершується через помилки часу виконання, пов'язані з MPI:

MPI_Abort (описувач області зв'язку, код помилки MPI);

Виклик MPI_Abort із будь-якої задачі примусово завершує роботу ВСІХ завдань, приєднаних до заданої області зв'язку. Якщо вказано описувач MPI_COMM_WORLD, буде завершено всю програму (всі її завдання) цілком, що, мабуть, і є найбільш правильним рішенням. Використовуйте код помилки MPI_ERR_OTHER, якщо не знаєте, як охарактеризувати помилку класифікації MPI.

Нормальне закриття бібліотеки:

Слід вписувати цю інструкцію перед поверненням із програми, тобто:

ü перед викликом стандартної функції Сі exit;

ü перед кожним після MPI_Init оператором return у функції main;

ü якщо функції main призначено тип void, і вона не закінчується оператором return, то MPI_Finalize() слід поставити в кінець main.

Дві інформаційні функції: повідомляють розмір групи (тобто загальна кількість завдань, приєднаних до її галузі зв'язку) та порядковий номер зухвалої задачі:

Приклад застосування цих функцій міститься у файлі “pi_mpi.c” – знаходження числа Пі. У ньому використовуються, окрім уже знайомих функцій, MPI_Bcast та MPI_Reduce. Ці функції розглядаються у параграфах: MPI_Bcast - Функції колективного обміну даними; MPI_Reduce – Функції підтримкирозподілених операцій).

2.4. Зв'язок "крапка-крапка"

Це найпростіший тип зв'язку між завданнями: одна гілка викликає функцію передачі, а інша - функцію прийому. У MPI це виглядає, наприклад, так:

Завдання 1 передає:

MPI_Send(buf, 5, MPI_INT, 1, 0, MPI_COMM_WORLD);

Завдання 2 приймає:

MPI_Recv( buf, 10, MPI_INT, 0, 0, MPI_COMM_WORLD, &status );

1.Адреса буфера, з якого в задачі 1 беруться, а в задачі 2 поміщаються дані. Пам'ятайте, що набори даних у кожного завдання свої, тому, наприклад, використовуючи одне й те саме ім'я масиву в кількох завданнях, Ви вказуєте не одну й ту саму область пам'яті, а різні, ніяк не пов'язані один з одним.

2. Розмір буфера. Задається над байтах, а кількості комірок. Для MPI_Send вказує, скільки осередків потрібно передати (у прикладі передаються 5 чисел). MPI_Recv означає максимальну ємність приймального буфера. Якщо фактична довжина повідомлення, що надійшло менше - останні осередки буфера залишаться недоторканими, якщо більше - відбудеться помилка часу виконання.

3. Тип осередку буфера. MPI_Send та MPI_Recv оперують масивами однотипних даних. Для опису базових типів Сі в MPI визначено константи MPI_INT, MPI_CHAR, MPI_DOUBLE тощо, мають тип MPI_Datatype. Їх назви утворюються префіксом " MPI_ " і ім'ям відповідного типу (int, char, double, . ), записаним великими літерами. Користувач може "реєструвати" в MPI свої типи даних, наприклад, структури, після чого MPI зможе обробляти їх нарівні з базовими.

4.Номер задачі, з якою відбувається обмін даними. Всі завдання всередині створеної групи MPI автоматично нумеруються від 0 до (розмір групи-1). У прикладі задача 0 передає задачі 1, задача 1 приймає від 0 задачі.

5. Ідентифікатор повідомлення. Це ціле число від 0 до 32 767, яке користувач вибирає сам. Воно служить тієї ж мети, що і, наприклад, розширення файлу - завдання-приймач:

ü за ідентифікатором визначає зміст прийнятої інформації;

ü повідомлення, які прийшли у невідомому порядку, може вилучати із загального вхідного потоку в потрібному алгоритмі порядку. Хорошим тоном є позначення ідентифікаторів символьними іменами за допомогою операторів #define або const int.

6.Описувач галузі зв'язку (комунікатор). Має бути однаковим для MPI_Send і MPI_Recv.

7.Статус завершення прийому. Містить інформацію про прийняте повідомлення: його ідентифікатор, номер завдання-передавача, код завершення і кількість даних, що фактично прийшли.

2.5. Прийом та передача: MPI_Sendrecv

Деякі конструкції з прийомом-передачею застосовуються дуже часто. Приклад – обмін даними із сусідами по групі (для парної кількості гілок у групі):

/* Гілки з парними номерами спочатку

* передають наступним непарним гілкам,

* потім приймають від попередніх

MPI_Send(. ( rank+1 ) % size . );

MPI_Recv(. ( rank+size-1 ) % size . );

/* Непарні гілки надходять навпаки:

* спочатку приймають від попередніх гілок,

* Потім передають наступним.

MPI_Recv(. ( rank-1 ) % size . );

MPI_Send(. ( rank+1 ) % size . );

Інший приклад – посилка даних та отримання підтвердження:

MPI_Send(. anyRank . ); /* Надсилаємо дані */

MPI_Recv(. anyRank . ); /* Приймаємо підтвердження */

Ситуація настільки поширена, що MPI спеціально введено дві функції, здійснюють одночасно посилку одних даних і прийом інших. Перша з них – MPI_Sendrecv. Вона має 12 параметрів:перші 5 параметрів такі ж, як у MPI_Send, решта 7 параметрів такі ж, як у MPI_Recv. Один її виклик робить ті ж дії, для яких у першому фрагменті потрібен блок IF-ELSE з чотирма викликами. Слід врахувати, що:

ü і прийом, і передача використовують один і той самий комунікатор;

ü порядок прийому та передачі даних MPI_Sendrecv вибирає автоматично; гарантується, що автоматичний вибір не призведе до "клінчу";

ü MPI_Sendrecv сумісна з MPI_Send і MPI_Recv, тобто може "спілкуватися" з ними.

MPI_Sendrecv_replace крім загального комунікатора використовує ще й загальний для приймання-передачі буфер. Не дуже зручно, що параметр count отримує подвійне тлумачення: це і кількість даних, що надсилаються, і гранична ємність вхідного буфера. Показання до застосування:

ü дані, що приймаються, повинні бути свідомо НЕ ДОВНІШЕ відправляються;

ü прийняті та надіслані дані повинні мати однаковий тип;

ü дані, що надсилаються, затираються прийнятими.

MPI_Sendrecv_replace також гарантовано не викликає клінчу.

Клінч (deadlock, глухий кут) – процес перебуває у стані глухого кута, якщо очікує події, яка ніколи не відбудеться. Приклад клінчу:

-- Гілка 1 -- -- Гілка 2 --

Recv (з гілки 2) Recv (з гілки 1)

Send (у гілку 2) Send (у гілку 1)

Це викличе клінч: функція прийому не поверне керування доти, доки не отримає дані; тому функція передачі не може розпочати відправлення даних; тому функція прийому. і так до самого SIG_KILL.

Колективні функції

Під терміном "колективні" в MPI маються на увазі три групи функцій:

ü функції колективного обміну даними;

ü точки синхронізації, або бар'єри;

ü функції підтримкирозподілених операцій.

Колективна функція однією з аргументів отримує описувач області зв'язку (комунікатор). Виклик колективної функції є коректним, тільки якщо зроблено з усіх процесів-абонентів відповідної галузі зв'язку, і саме з цим комунікатором як аргумент (хоча для однієї області зв'язку може бути кілька комунікаторів, підставляти їх замість один одного не можна). У цьому полягає колективність: або функція викликається всім колективом процесів, або ніким; третього не дано.

Для обмеження області дії колективної функції частиною гілок створюється тимчасова група/область зв'язку/комунікатор на базі існуючих, як це показано в розділі про комунікатори.