Здавалка
Главная | Обратная связь

Общая организация MPI.



Директивы и функции

Значительная часть функциональности OpenMP реализуется при помощи директив компилятору. Они должны быть явно вставлены пользователем, что позволит выполнять программу в параллельном режиме. Директивы OpenMP в программах на языке Фортран оформляются комментариями и начинаются с комбинации символов !$OMP , C$OMP или *$OMP , а в языке Си — указаниями препроцессору, начинающимися с #pragma omp . Ключевое слово omp используется для того, чтобы исключить случайные совпадения имён директив OpenMP с другими именами.

Формат директивы на Си/Си++:

 

#pragma omp directive-name [опция[[,] опция]...]

 

Формат директивы на Фортране:

 

!$OMP directive-name [опция[[,] опция]...]

С$OMP directive-name [опция[[,] опция]...]

*$OMP directive-name [опция[[,] опция]...]

 

Все директивы OpenMP можно разделить на 3 категории: определение параллельной области, распределение работы, синхронизация. Каждая директива может иметь несколько дополнительных атрибутов – опций (clause). Отдельно специфицируются опции для назначения классов переменных, которые могут быть атрибутами различных директив.

Чтобы задействовать функции библиотеки OpenMP периода выполнения (исполняющей среды), в программу нужно включить заголовочный файл omp.h (для программ на языке Фортран – файл omp_lib.h или модуль omp_lib ). Если вы используете в приложении только OpenMP-директивы, включать этот файл не требуется. Функции назначения параметров имеют приоритет над соответствующими переменными окружения.

 

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

В момент запуска программы порождается единственная нить-мастер или «основная» нить, которая начинает выполнение программы с первого оператора. Основная нить и только она исполняет все последовательные области программы. При входе в параллельную область порождаются дополнительные нити.

 

Директива parallel

 

Параллельная область задаётся при помощи директивы parallel ( parallel ... end parallel ).

Си:

#pragma omp parallel [опция[[,] опция]...]

Фортран:

!$omp parallel [опция[[,] опция]...]

<код параллельной области>

!$omp end parallel

 

Возможные опции:

· if(условие) – выполнение параллельной области по условию. Вхождение в параллельную область осуществляется только при выполнении некоторого условия. Если условие не выполнено, то директива не срабатывает и продолжается обработка программы в прежнем режиме;

· num_threads (целочисленное выражение) – явное задание количества нитей, которые будут выполнять параллельную область; по умолчанию выбирается последнее значение, установленное с помощью функции omp_set_num_threads(), или значение переменной OMP_NUM_THREADS ;

· default(private|firstprivate|shared|none) – всем переменным в параллельной области, которым явно не назначен класс, будет назначен класс private , firstprivate или shared соответственно; none означает, что всем переменным в параллельной области класс должен быть назначен явно; в языке Си задаются только варианты shared или none ;

· private(список) – задаёт список переменных, для которых порождается локальная копия в каждой нити; начальное значение локальных копий переменных из списка не определено;

· firstprivate(список) – задаёт список переменных, для которых порождается локальная копия в каждой нити; локальные копии переменных инициализируются значениями этих переменных в нити-мастере;

· shared(список) – задаёт список переменных, общих для всех нитей;

· copyin(список) – задаёт список переменных, объявленных как threadprivate , которые при входе в параллельную область инициализируются значениями соответствующих переменных в нити-мастере;

· reduction(оператор:список) – задаёт оператор и список общих переменных; для каждой переменной создаются локальные копии в каждой нити; локальные копии ициализируются соответственно типу оператора (для аддитивных операций – 0 или его аналоги, для мультипликативных операций – 1 или её аналоги); над локальными копиями

переменных после выполнения всех операторов параллельной области выполняется заданный оператор; оператор это: для языка Си – + , * , - , & , | , ^ , && , || , для языка Фортран – + , * , - , .and. , .or. , .eqv. , .neqv. , max , min , iand , ior , ieor ; порядок выполнения операторов не определён, поэтому результат может отличаться от запуска к запуску.

При входе в параллельную область порождаются новые OMP_NUM_THREADS-1 нитей, каждая нить получает свой уникальный номер, причём порождающая нить получает номер 0 и становится основной нитью группы («мастером»). Остальные нити получают в качестве номера целые числа с 1 до OMP_NUM_THREADS-1 . Количество нитей, выполняющих данную параллельную область, остаётся неизменным до момента выхода из области. При выходе из параллельной области производится неявная синхронизация и уничтожаются все нити, кроме породившей.

Пример демонстрирует применение опции reduction . В данном примере производится подсчет общего количества порождённых нитей. Каждая нить инициализирует локальную копию переменной count значением 0 . Далее, каждая нить увеличивает значение собственной копии переменной count на единицу и выводит полученное число. На выходе из параллельной области происходит суммирование значений переменных count по всем нитям, и полученная величина становится новым значением переменной count в последовательной области.

 

//Опция reduction на языке Си.

#include <stdio.h>

int main(int argc, char *argv[])

{

int count = 0;

#pragma omp parallel reduction (+: count)

{

count++;

printf("Текущее значение count: %d\n", count);

}

printf("Число нитей: %d\n", count);

}

 

!Опция reduction на языке fortran.

program example4b

integer count

count=0

!$omp parallel reduction (+: count)

count=count+1

print *, "Текущее значение count: ", count

!$omp end parallel

print *, "Число нитей: ", count

end

В некоторых случаях система может динамически изменять количество нитей, используемых для выполнения параллельной области, например, для оптимизации спользования ресурсов системы. Это разрешено делать, если переменная среды OMP_DYNAMIC установлена в true.

 

Переменную OMP_DYNAMIC можно установить с помощью функции omp_set_dynamic() .

Си:

void omp_set_dynamic(int num);

Фортран:

subroutine omp_set_dynamic(num)

logical num

На языке Си в качестве значения параметра функции omp_set_dynamic() задаётся 0 или 1 , а на языке Фортран – .FALSE. или .TRUE. Если система не поддерживает динамическое изменение количества нитей, то при вызове функции omp_set_dynamic() значение переменной OMP_DYNAMIC не изменится

Узнать значение переменной OMP_DYNAMIC можно при помощи функции omp_get_dynamic() .

Си:

int omp_get_dynamic(void);

Фортран:

logical function omp_get_dynamic()

 

Функция omp_get_max_threads() возвращает максимально допустимое число нитей для использования в следующей параллельной области.

Си:

int omp_get_max_threads(void);

Фортран:

integer function omp_get_max_threads()

Функция omp_get_num_procs() возвращает количество процессоров, доступных для использования программе пользователя на момент вызова. Нужно учитывать, что количество доступных процессоров может динамически изменяться.

Си:

int omp_get_num_procs(void);

Фортран:

integer function omp_get_num_procs()

Параллельные области могут быть вложенными; по умолчанию вложенная параллельная область выполняется одной нитью. Это управляется установкой переменной среды OMP_NESTED .

Изменить значение переменной OMP_NESTED можно с помощью вызова функции omp_set_nested() .

Си:

void omp_set_nested(int nested) ;

Фортран:

subroutine omp_set_nested(nested)

logical nested

Функция omp_set_nested() разрешает или запрещает вложенный параллелизм. На языке Си в качестве значения параметра задаётся 0 или 1 , а на языке Фортран – .FALSE. или .TRUE. Если вложенный параллелизм разрешён, то каждая нить, в которой встретится описание параллельной области, породит для её выполнения новую группу нитей. Сама породившая нить станет в новой группе нитью-мастером. Если система не поддерживает вложенный параллелизм, данная функция не будет иметь эффекта.

 

Директива single

Если в параллельной области какой-либо участок кода должен быть выполнен лишь один раз, то его нужно выделить директивами single ( single ... end single ).

Си:

#pragma omp single [опция [[,] опция]...]

Фортран:

!$omp single [опция [[,] опция]...]

<код для одной нити>

!$omp end single [опция [[,] опция]...]

 

Возможные опции:

· private(список) – задаёт список переменных, для которых порождается локальная копия в каждой нити; начальное значение локальных копий переменных из списка не определено;

· firstprivate(список) – задаёт список переменных, для которых порождается локальная копия в каждой нити; локальные копии переменных инициализируются значениями этих переменных в нити-мастере;

· copyprivate(список) – после выполнения нити, содержащей конструкцию single , новые значения переменных списка будут доступны всем одноименным частным переменным ( private и firstprivate ), описанным в начале параллельной области и используемым всеми её нитями; опция не может использоваться совместно с опцией nowait ; переменные списка не должны быть перечислены в опциях private и firstprivate данной директивы single ;

· nowait – после выполнения выделенного участка происходит неявная барьерная синхронизация параллельно работающих нитей: их дальнейшее выполнение происходит только тогда, когда все они достигнут данной точки; если в подобной задержке нет необходимости, опция nowait позволяет нитям, уже дошедшим до конца участка, продолжить выполнение без синхронизации с остальными.

 

Пример иллюстрирует применение директивы single вместе с опцией nowait . Сначала все нити напечатают текст "Сообщение 1" , при этом одна нить (не обязательно нить-мастер) дополнительно напечатает текст "Одна нить" . Остальные нити, не дожидаясь завершения выполнения области single , напечатают текст "Сообщение 2" . Таким образом, первое появление "Сообщение 2" в выводе может встретиться как до текста "Одна нить" , так и после него. Если убрать опцию nowait , то по окончании области single произойдёт барьерная синхронизация, и ни одна выдача "Сообщение 2" не может появиться до выдачи "Одна нить".

//Директива single и опция nowait на языке Си.

#include <stdio.h>

int main(int argc, char *argv[])

{

#pragma omp parallel

{

printf("Сообщение 1\n");

#pragma omp single nowait

{

printf("Одна нить\n");

}

printf("Сообщение 2\n");

} }

Директива master

Директивы master ( master ... end master ) выделяют участок кода, который будет выполнен только нитью-мастером. Остальные нити просто пропускают данный участок и продолжают работу с оператора, расположенного следом за ним. Неявной синхронизации данная директива не предполагает.

Си:

#pragma omp master

Фортран:

!$omp master

<код для нити-мастера>

!$omp end master

 

Модель данных

Модель данных в OpenMP предполагает наличие как общей для всех нитей области памяти, так и локальной области памяти для каждой нити. В OpenMP переменные в параллельных областях программы разделяются на два основных класса:

· shared (общие; все нити видят одну и ту же переменную);

· private (локальные, приватные; каждая нить видит свой экземпляр данной переменной).

Отдельные правила определяют назначение классов переменных при входе и выходе из параллельной области или параллельного цикла при использовании опций reduction , firstprivate , lastprivate , copyin .

 

Пример демонстрирует работу функций omp_get_num_threads() и omp_get_thread_num() . Нить, порядковый номер которой равен 0 , напечатает общее количество порождённых нитей, а остальные нити напечатают свой порядковый номер:

#include <stdio.h>

#include <omp.h>

int main(int argc, char *argv[])

{

int count, num;

#pragma omp parallel

{

count=omp_get_num_threads();

num=omp_get_thread_num();

if (num == 0) printf("Всего нитей: %d\n", count);

else printf("Нить номер %d\n", num);

}

}

 

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

Если в параллельной области встретился оператор цикла, то, согласно общему правилу, он будет выполнен всеми нитями текущей группы, то есть каждая нить выполнит все итерации данного цикла. Для распределения итераций цикла между различными нитями можно использовать директиву for ( do ... [end do] ).

Си:

#pragma omp for [опция [[,] опция]...]

Фортран:

!$omp do [опция [[,] опция]...]

<блок циклов do>

[!$omp end do [nowait]]

Эта директива относится к идущему следом за данной директивой блоку, включающему операторы for ( do ).

 

Возможные опции:

· private(список) – задаёт список переменных, для которых порождается локальная копия в каждой нити; начальное значение локальных копий переменных из списка не определено;

· firstprivate(список) – задаёт список переменных, для которых порождается локальная копия в каждой нити; локальные копии переменных инициализируются значениями этих переменных в нити-мастере;

· lastprivate(список) – переменным, перечисленным в списке, присваивается результат с последнего витка цикла;

· reduction(оператор:список) – задаёт оператор и список общих переменных; для каждой переменной создаются локальные копии в каждой нити; локальные копии инициализируются соответственно типу оператора (для аддитивных операций – 0 или его аналоги, для мульти пликативных операций – 1 или её аналоги); над локальными копиями переменных после завершения всех итераций цикла выполняется заданный оператор; оператор это: для языка Си – + , * , - , & , | , ^ , && , || , для языка Фортран – + , * , - , .and. , .or. , .eqv. , .neqv. , max , min , iand , ior , ieor ; порядок выполнения операторов не определён, поэтому результат может отличаться от запуска к запуску;

· schedule(type[, chunk]) – опция задаёт, каким образом итерации цикла распределяются между нитями;

· collapse(n) — опция указывает, что n последовательных тесновложенных циклов ассоциируется с данной директивой; для циклов образуется общее пространство итераций, которое делится между нитями; если опция collapse не задана, то директива относится только к одному непосредственно следующему за ней циклу;

· ordered – опция, говорящая о том, что в цикле могут встречаться директивы ordered ; в этом случае определяется блок внутри тела цикла, который должен выполняться в том порядке, в котором итерации идут в последовательном цикле;

· nowait – в конце параллельного цикла происходит неявная барьерная синхронизация параллельно работающих нитей: их дальнейшее выполнение происходит только тогда, когда все они достигнут данной точки; если в подобной задержке нет необходимости, опция nowait позволяет нитям, уже дошедшим до конца цикла, продолжить выполнение без синхронизации с остальными. Если директива end do в явном виде не указана, то в конце параллельного цикла синхронизация все равно будет выполнена.

 

В опции schedule параметр type задаёт следующий тип распределения итераций:

· static – блочно-циклическое распределение итераций цикла; размер блока – chunk . Первый блок из chunk итераций выполняет нулевая нить, второй блок — следующая и т.д. до последней нити, затем распределение снова начинается с нулевой нити. Если значение chunk не указано, то всё множество итераций делится на непрерывные куски примерно одинакового размера (конкретный способ зависит от реализации), и полученные порции итераций распределяются между нитями.

· dynamic – динамическое распределение итераций с фиксированным размером блока: сначала каждая нить получает chunk итераций (по умолчанию chunk=1 ), та нить, которая заканчивает выполнение своей порции итераций, получает первую свободную порцию из chunk итераций. Освободившиеся нити получают новые порции итераций до тех пор, пока все порции не будут исчерпаны. Последняя порция может содержать меньше итераций, чем все остальные.

· guided – динамическое распределение итераций, при котором размер порции уменьшается с некоторого начального значения до величины chunk (по умолчанию chunk=1 )пропорционально количеству ещё не распределённых итераций, делённому на количество нитей, выполняющих цикл. Размер первоначально выделяемого блока зависит от реализации. В ряде случаев такое распределение позволяет аккуратнее разделить работу и сбалансировать загрузку нитей. Количество итераций в последней порции может оказаться меньше значения chunk .

· auto – способ распределения итераций выбирается компилятором и/или системой выполнения. Параметр chunk при этом не задаётся.

· runtime – способ распределения итераций выбирается во время работы программы по значению переменной среды OMP_SCHEDULE . Параметр chunk при этом не задаётся.

 

Синхронизация

 

Целый набор директив в OpenMP предназначен для синхронизации работы нитей.

Барьер

Самый распространенный способ синхронизации в OpenMP – барьер. Он оформляется с помощью директивы barrier .

 

Си:

#pragma omp barrier

Фортран:

!$omp barrier

 

Нити, выполняющие текущую параллельную область, дойдя до этой директивы, останавливаются и ждут, пока все нити не дойдут до этой точки программы, после чего разблокируются и продолжают работать дальше. Кроме того, для разблокировки необходимо, чтобы все синхронизируемые нити завершили все порождённые ими задачи ( task ).

 

program example24b

include "omp_lib.h"

!$omp parallel

print *, "Сообщение 1"

print *, "Сообщение 2"

!$omp barrier

print *, "Сообщение 3"

!$omp end parallel

end

 

Пример демонстрирует применение директивы barrier . Директива barrier используется для упорядочивания вывода от работающих нитей. Выдачи с разных нитей "Сообщение 1" и "Сообщение 2" могут перемежаться в произвольном порядке, а выдача "Сообщение 3" со всех нитей придёт строго после двух предыдущих выдач.

 

 

Директивы ordered ( ordered ... end ordered ) определяют блок внутри тела цикла, который должен выполняться в том порядке, в котором итерации идут в последовательном цикле.

Си:

#pragma omp ordered

Фортран:

!$omp ordered

<блок операторов>

!$omp end ordered

 

Блок операторов относится к самому внутреннему из объемлющих циклов, а в параллельном цикле должна быть задана опция ordered . Нить, выполняю ая первую итерацию цикла, выполняет операции данного блока. Нить, выполняющая любую следующую итерацию, должна сначала дождаться выполнения всех операций блока всеми нитями, выполняющими предыдущие итерации. Может использоваться, например, для упорядочения вывода от параллельных нитей.

Пример иллюстрирует применение директивы ordered и опции ordered. Цикл for ( do ) помечен как ordered . Внутри тела цикла идут две выдачи – одна вне блока ordered , а вторая – внутри него. В результате первая выдача получается неупорядоченной, а вторая идёт в строгом порядке по возрастанию номера итерации.

 

#include <stdio.h>

#include <omp.h>

int main(int argc, char *argv[])

{

int i, n;

#pragma omp parallel private (i, n)

{

n=omp_get_thread_num();

#pragma omp for ordered

for (i=0; i<5; i++)

{

printf("Нить %d, итерация %d\n", n, i);

#pragma omp ordered

{

printf("ordered: Нить %d, итерация %d\n", n, i);

}

}

}

}

 

Критические секции

С помощью директив critical ( critical ... end critical ) оформляется критическая секция программы.

Си:

#pragma omp critical [(<имя_критической_секции>)]

Фортран:

!$omp critical [(имя)]

<код критической секции>

!$omp end critical [(имя)]

В каждый момент времени в критической секции может находиться не более одной нити. Если критическая секция уже выполняется какой-либо нитью, то все другие нити, выполнившие директиву для секции с данным именем, будут заблокированы, пока вошедшая нить не закончит выполнение данной критической секции. Как только работавшая нить выйдет из критической секции, одна из заблокированных на входе нитей войдет в неё. Если на входе в критическую секцию стояло несколько нитей, то случайным образом выбирается одна из них, а остальные заблокированные нити продолжают ожидание.

Все неименованные критические секции условно ассоциируются с одним и тем же именем. Все критические секции, имеющие одно и тоже имя, рассматриваются единой секцией, даже если находятся в разных параллельных областях. Побочные входы и выходы из критической секции запрещены.

 

Пример иллюстрирует применение директивы critical . Переменная n объявлена вне параллельной области, поэтому по умолчанию является общей. Критическая секция позволяет разграничить доступ к переменной n . Каждая нить по очереди присвоит n свой номер и затем напечатает полученное значение.

 

#include <stdio.h>

#include <omp.h>

int main(int argc, char *argv[])

{

int n;

#pragma omp parallel

{

#pragma omp critical

{

n=omp_get_thread_num();

printf("Нить %d\n", n);

}

}

}

Если бы в примере 26 не была указана директива critical , результат выполнения программы был бы непредсказуем. С директивой critical порядок вывода результатов может быть произвольным, но это всегда будет набор одних и тех же чисел от 0 до OMP_NUM_THREADS-1 . Конечно, подобного же результата можно было бы добиться другими способами, например, объявив переменную n локальной, тогда каждая нить работала бы со своей копией этой переменной. Однако в исполнении этих фрагментов разница существенная.

Если есть критическая секция, то в каждый момент времени фрагмент будет обрабатываться лишь какой-либо одной нитью. Остальные нити, даже если они уже подошли к данной точке программы и готовы к работе, будут ожидать своей очереди. Если критической секции нет, то все нити могут одновременно выполнить данный участок кода. С одной стороны, критические секции предоставляют удобный механизм для работы с общими переменными. Но с другой стороны, пользоваться им нужно осмотрительно, поскольку критические секции добавляют последовательные участки кода в параллельную программу, что может снизить её эффективность.

 

Директива atomic

Частым случаем использования критических секций на практике является обновление общих переменных. Например, если переменная sum является общей и оператор вида sum=sum+expr находится в параллельной области программы, то при одновременном выполнении данного оператора несколькими нитями можно получить некорректный результат. Чтобы избежать такой ситуации можно воспользоваться механизмом критических секций или специально предусмотренной для таких случаев директивой atomic.

 

Си:

#pragma omp atomic

Фортран:

!$omp atomic

Данная директива относится к идущему непосредственно за ней оператору присваивания (на используемые в котором конструкции накладываются достаточно понятные ограничения), гарантируя корректную работу с общей переменной, стоящей в его левой части. На время выполнения оператора блокируется доступ к данной переменной всем запущенным в данный момент нитям, кроме нити, выполняющей операцию. Атомарной является только работа с переменной в левой части оператора присваивания, при этом вычисления в правой части не обязаны быть атомарными.

 

Директива flush

Поскольку в современных параллельных вычислительных системах может использоваться сложная структура и иерархия памяти, пользователь должен иметь гарантии того, что в необходимые ему моменты времени все нити будут видеть единый согласованный образ памяти. Именно для этих целей и предназначена директива flush .

Си:

#pragma omp flush [(список)]

Фортран:

!$omp flush [(список)]

Выполнение данной директивы предполагает, что значения всех переменных (или переменных из списка, если он задан), временно хранящиеся в регистрах и кэш-памяти текущей нити, будут занесены в основную память; все изменения переменных, сделанные нитью во время работы, станут видимы остальным нитям; если какая-то информация хранится в буферах вывода, то буферы будут сброшены и т.п. При этом операция производится только с данными вызвавшей нити, данные, изменявшиеся другими нитями, не затрагиваются. Поскольку выполнение данной директивы в полном объёме может повлечь значительных накладных расходов, а в данный момент нужна гарантия согласованного представления не всех, а лишь отдельных переменных, то эти переменные можно явно перечислить в директиве списком. До полного завершения операции никакие действия с перечисленными в ней переменными не могут начаться.

 

 

Основы MPI

Общая организация MPI.

MPI-программа представляет собой набор независимых процессов, каждый из которых выполняет свою собственную программу (не обязательно одну и ту же), написанную на языке C или FORTRAN. Процессы MPI-программы взаимодействуют друг с другом посредством вызова коммуникационных процедур. Как правило, каждый процесс выполняется в своем собственном адресном пространстве, однако допускается и режим разделения памяти. MPI не специфицирует модель выполнения процесса - это может быть как последовательный процесс, так и многопотоковый. MPI не предоставляет никаких средств для распределения процессов по вычислительным узлам и для запуска их на исполнение. Эти функции возлагаются либо на операционную систему, либо на программиста.

Для идентификации наборов процессов вводится понятие группы, объединяющей все или какую-то часть процессов. Каждая группа образует область связи, с которой связывается специальный объект - коммуникатор области связи. Процессы внутри группы нумеруются целым числом в диапазоне 0..groupsize-1. Все коммуникационные операции с некоторым коммуникатором будут выполняться только внутри области связи, описываемой этим коммуникатором. При инициализации MPI создается предопределенная область связи, содержащая все процессы MPI-программы, с которой связывается предопределенный коммуникатор MPI_COMM_WORLD.

Итак, если сформулировать коротко, MPI - это библиотека функций, обеспечивающая взаимодействие параллельных процессов с помощью механизма передачи сообщений. Это достаточно объемная и сложная библиотека, состоящая примерно из 130 функций, в число которых входят:

· функции инициализации и закрытия MPI процессов;

· функции, реализующие коммуникационные операции типа точка-точка;

· функции, реализующие коллективные операции;

· функции для работы с группами процессов и коммуникаторами;

· функции для работы со структурами данных;

· функции формирования топологии процессов.

В принципе, любая параллельная программа может быть написана с использованием всего 6 MPI функций, а достаточно полную и удобную среду программирования составляет набор из 24 функций.

Каждая из MPI функций характеризуется способом выполнения:

1. Локальная функция - выполняется внутри вызывающего процесса. Ее завершение не требует коммуникаций.

2. Нелокальная функция - для ее завершения требуется выполнение MPI-процедуры другим процессом.

3. Глобальная функция - процедуру должны выполнять все процессы группы. Несоблюдение этого условия может приводить к зависанию задачи.

4. Блокирующая функция - возврат управления из процедуры гарантирует возможность повторного использования параметров, участвующих в вызове. Никаких изменений в состоянии процесса, вызвавшего блокирующий запрос, до выхода из процедуры не может происходить.

5. Неблокирующая функция - возврат из процедуры происходит немедленно, без ожидания окончания операции и до того, как будет разрешено повторное использование параметров, участвующих в запросе. Завершение неблокирующих операций осуществляется специальными функциями.

Использование библиотеки MPI имеет некоторые отличия в языках C и FORTRAN.

В языке C все процедуры являются функциями, и большинство из них возвращает код ошибки. При использовании имен подпрограмм и именованных констант необходимо строго соблюдать регистр символов. Массивы индексируются с 0. Логические переменные представляются типом int (true соответствует 1, а false - 0). Определение всех именованных констант, прототипов функций и определение типов выполняется подключением файла mpi.h. Введение собственных типов в MPI было продиктовано тем обстоятельством, что стандартные типы языков на разных платформах имеют различное представление. MPI допускает возможность запуска процессов параллельной программы на компьютерах различных платформ, обеспечивая при этом автоматическое преобразование данных при пересылках. В таблице ниже приведено соответствие предопределенных в MPI типов стандартным типам языка С.

Соответствие между MPI-типами и типами языка C

Тип MPI Тип языка C
MPI_CHAR signed char
MPI_SHORT signed short int
MPI_INT signed int
MPI_LONG signed long int
MPI_UNSIGNED_CHAR unsigned char
MPI_UNSIGNED_SHORT unsigned short int
MPI_UNSIGNED unsigned int
MPI_UNSIGNED_LONG unsigned long int
MPI_FLOAT float
MPI_DOUBLE double
MPI_LONG_DOUBLE long double
MPI_BYTE  
MPI_PACKED  

В языке FORTRAN большинство MPI-процедур являются подпрограммами (вызываются с помощью оператора CALL), а код ошибки возвращают через дополнительный последний параметр процедуры. Несколько процедур, оформленных в виде функций, код ошибки не возвращают. Не требуется строгого соблюдения регистра символов в именах подпрограмм и именованных констант. Массивы индексируются с 1. Объекты MPI, которые в языке C являются структурами, в языке FORTRAN представляются массивами целого типа. Определение всех именованных констант и определение типов выполняется подключением файла mpif.h. В таблице ниже приведено соответствие предопределенных в MPI типов стандартным типам языка FORTRAN.

Соответствие между MPI-типами и типами языка FORTRAN

Тип MPI Тип языка FORTRAN
MPI_INTEGER INTEGER
MPI_REAL REAL
MPI_DOUBLE_PRECISION DOUBLE PRECISION
MPI_COMPLEX COMPLEX
MPI_LOGICAL LOGICAL
MPI_CHARACTER CHARACTER(1)
MPI_BYTE  
MPI_PACKED  

В таблицах перечислен обязательный минимум поддерживаемых стандартных типов, однако, если в базовой системе представлены и другие типы, то их поддержку будет осуществлять и MPI, например, если в системе есть поддержка комплексных переменных двойной точности DOUBLE COMPLEX, то будет присутствовать тип MPI_DOUBLE_COMPLEX. Типы MPI_BYTE и MPI_PACKED используется для передачи двоичной информации без какого-либо преобразования. Кроме того, программисту предоставляются средства создания собственных типов на базе стандартных.







©2015 arhivinfo.ru Все права принадлежат авторам размещенных материалов.