Характеристики на рамкиране
Има няколко функции, които се използват във всяко, дори и най-краткото MPI приложение. Те се занимават не толкова с реалното предаване на данни, колкото с предоставянето им:
Инициализиране на библиотеката. Една от първите инструкции в основната функция (основната функция на приложението):
Срив на библиотеката. Извиква се, ако потребителската програма се прекрати поради свързани с MPI грешки по време на изпълнение:
MPI_Abort(дескриптор на областта на връзката, MPI код на грешка);
Извикването на MPI_Abort от която и да е задача принудително ще прекрати ВСИЧКИ задачи, свързани към посочената област на връзка. Ако е указан дескрипторът MPI_COMM_WORLD, цялото приложение (всички негови задачи) ще бъде прекратено, което очевидно е най-правилното решение. Използвайте кода за грешка MPI_ERR_OTHER, ако не сте сигурни как да характеризирате грешка в MPI класификацията.
Нормално затваряне на библиотеката:
Трябва да въведете тази инструкция, преди да се върнете от програмата, а именно:
ü преди извикване на стандартната C функция за изход;
ü преди всеки оператор return след MPI_Init в основната функция;
ü ако на функцията main е присвоен тип void и тя не завършва с израз за връщане, тогава MPI_Finalize() трябва да се постави в края на main.
Две информационни функции: отчетете размера на групата (т.е. общия брой задачи, свързани с нейната област на връзка) и поредния номер на извикващата задача:
Пример за използването на тези функции е във файла “pi_mpi.c” - намиране на числото Pi. Той използва, в допълнение към вече познатите функции, 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, &състояние);
1. Адресът на буфера, от който се вземат данни в задача 1 и данните се поставят в задача 2. Не забравяйте, че всяка задача има свои собствени набори от данни, следователно, например, използвайки едно и също име на масив в няколко задачи, вие посочвате не една и съща област на паметта, а различни, които не са свързани помежду си по никакъв начин.
2. Размер на буфера. Посочва се не в байтове, а в броя на клетките. За MPI_Send указва колко клетки да бъдат изпратени (в примера се изпращат 5 числа). В MPI_Recv означава максималния капацитет на приемния буфер. Ако действителната дължина на входящото съобщение е по-малка - последните клетки на буфера ще останат непокътнати, ако е по-голяма - ще възникне грешка по време на изпълнение.
3. Тип буферна клетка. MPI_Send и MPI_Recv работят с масиви от същия тип данни. За да опише основните C типове, 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 до 32767, което потребителят избира. Той служи за същата цел като например файловото разширение - целева задача:
ü чрез идентификатор определя значението на получената информация;
ü Съобщенията, пристигнали в неизвестен ред, могат да бъдат извлечени от общия входен поток в реда, изискван от алгоритъма. Добра практика е да обозначавате идентификатори със символни имена, като използвате операторите "#define" или "const int".
6. Описание на комуникационната област (комуникатор). Трябва да е същото за MPI_Send и MPI_Recv.
7. Състоянието на завършване на рецепцията. Съдържа информация за полученото съобщение: неговия идентификатор, номера на задачата на изпращача, кода за завършване и количеството действително получени данни.
2.5. Получаване и предаване: MPI_Sendrecv
Някои проекти за предаване и приемане се използват много често. Пример - обмен на данни със съседи в група (за четен брой клонове в група):
/* Първо четните клонове
* преминете към следващите нечетни клонове,
* след това приемете от предишните
MPI_Send(. (ранг+1) % размер.);
MPI_Recv(. (ранг+размер-1) % размер.);
/* Странните клонове правят обратното:
* първо вземане от предишни клонове,
* след това се преминава към следващия.
MPI_Recv(. (ранг-1) % размер.);
MPI_Send(. (ранг+1) % размер.);
Друг пример е изпращане на данни и получаване на потвърждение:
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, в допълнение към общия комуникатор, използва и общ буфер за приемане и предаване. Не е много удобно параметърът за броене да получава двойна интерпретация: това е едновременно количеството изпратени данни и максималният капацитет на входния буфер. Показания за употреба:
ü получените данни трябва да са явно НЕ ПО-ДЪЛГИ от изпратените;
ü получените и изпратените данни трябва да са от един и същи тип;
Изпратените данни се презаписват от получените данни.
MPI_Sendrecv_replace също е гарантирано, че няма да предизвика клинч.
Клинч (deadlock, deadlock) - процесът е в състояние на безизходица, ако чака събитие, което никога няма да се случи. пример за клинч:
-- Клон 1 -- -- Клон 2 --
Recv(от клон 2) Recv(от клон 1)
Изпрати( до клон 2 ) Изпрати( до клон 1 )
Това ще доведе до затруднение: функцията за получаване няма да се върне, докато не получи данни; следователно функцията за изпращане не може да започне да изпраща данни; така че функцията за получаване. и така до самия SIG_KILL.
Колективни функции
Терминът "колективен" в MPI се отнася до три групи функции:
ü функции за колективен обмен на данни;
ü точки на синхронизация или бариери;
ü поддържащи функцииразпределени операции.
Колективната функция получава дескриптор на комуникационната област (комуникатор) като един от аргументите. Извикването на колективна функция е правилно само ако е направено от всички абонатни процеси на съответната област на свързване и с този комуникатор като аргумент (въпреки че може да има няколко комуникатора за една област на свързване, те не могат да бъдат заменени един с друг). Това е същността на колективността: или дадена функция се извиква от целия екип от процеси, или от никой; Трети няма.
За да се ограничи обхватът на колективната функция до част от клоновете, на базата на съществуващите се създава временна група/област за връзка/комуникатор, както е показано в раздела за комуникатори.