В.А.Фисун 13.03.97
Язык Фортран GNS для систем с распределенной памятью
Рекомендации по использованию языка

О Г Л А В Л Е Н И Е

1. Введение
2. Тип данных - TASKID
3. Задачи и процессы
3.1. Создание процессов
3.2. Завершение процессов и завершение программы
3.3. Ввод-вывод
4. Передача сообщений
4.1. Способы передачи сообщений
4.2. Идентификация абонентов
4.3. Операторы передачи сообщения
5. Конструкция выбора
6. Стандартные процедуры
7. Функции редукции
7.1. Использование функций редукции
7.2. Использование статической модели параллелизма
8. Литература

1. Введение

Данное руководство есть модификация описания Фортран GNS [1], языка программирования для вычислительных систем с распределенной памятью, дополненное комментариями об особенностях использования параллельных конструкций языка. Фортран GNS представляет собой расширение языка Фортран 77 средствами для образования параллельных процессов и обмена сообщениями между ними. За основу расширений приняты средства, предложенные в проекте стандарта, которые разработаны в Германии в рамках европейской программы ESPRIT. В общем случае, программа на языке Фортран GNS состоит из описания одной начальной задачи (главной программной единицы), и описания одной или нескольких других задач (программные единицы нового для Фортрана 77 вида). Вычислительные процессы, порожденные по описаниям задач, выполняются параллельно и взаимодействуют между собой при помощи аппарата передачи сообщений.

Выполнение программы начинается с выполнения главного процесса, образованного по описанию начальной задачи. Он порождает другие процессы, которые сразу же начинают выполняться и, в свою очередь, могут также порождать новые процессы. По одному описанию программной единицы-задачи может создаваться произвольное количество процессов. Так как процессу доступны только свои локальные данные, то процессы, образованные по одному образцу, могут приобретать индивидуальность, принимая информацию от других процессов и от каналов ввода. Обмен информацией между процессами (передача констант, скаляров и массивов всех определенных в языке типов) осуществляется с помощью операторов передачи сообщений. Предусмотрено три способа передачи сообщений: синхронный, асинхронный и "без ожидания". Каждый процесс имеет "почтовый ящик" для буферизации поступающих сообщений.
При порождении процессов должны быть заданы номера виртуальных "процессоров", на которых должны "выполняться" процессы, причем допускается размещение на одном процессоре несколько процессов. Средства отображения номеров виртуальных вычислителей на конфигурацию реальной вычислительной платформы не включены в язык,они оговариваются в инструкциях по запуску программ на конкретных установках. При этом требуется задать соответствие между номерами (именами) реальных процессоров платформы и виртуальными номерами, а, иногда, и уточниться именами задач, размещаемых на этих процессорах.
Сложность реализации динамической загрузки задач при параллельной работе на архитектуре МРР, наличие, как правило, при запуске программы информации об дислокации задач на процессорах, философия SPMD программирования (одна программа - много данных) привели к введению в рамках языка Фортран GNS "статической модели" параллелизма.
В этой схеме порождение и запуск всех параллельных задач программы - процессов производится одновременно при запуске программы. При этом, все задачи имеют равный статус (нет главной, дерева последовательности порождений процессов). Процедура порождения задач, функции определения имен главного, порождающего процесса теряют смысл. Завершение программы может быть произведено из любого процесса. Понятие номера виртуального процессора становится основным средством отображения: физический процессор -> виртуальные процессоры -> имена задач. На одном виртуальном процессоре может быть размещена только одна задача, но на одном физическом - несколько виртуальных.
Одновременно в язык вводятся средства - встроенные процедуры для определения топологии вычислительной платформы, имен, состава и дислокацию вычислительных процессов программы, механизм завершения программы. Используя эти средства любой процесс может проводить настройку на реальную вычислительную среду. Статическая и динамическая модели параллелизма сосуществуют в рамках одного языка: для каждого случая следует использовать соответствующие функции.
Реализация языка Fortran GNS может быть проведена на базе штатного компилятора Фортран 77, входящего в состав программного обеспечения вычислительной системы,и библиотеки системной поддержки для интерпретации параллельных конструкций языка. При этом тексты на языке Fortran GNS отображаются в тексты на языке Фортран 77, содержащие обращения к программам библиотеки поддержки. Одним из вариантов такого отображения является описание языка Фортран МВК [3]. Преобразование текстов программ может производиться вручную или с помощью разработанного для этого конвертора Fortran GNS -> Фортран МВК.

2. Тип данных - TASKID

По семантике языка Fortran GNS все процессы программы получают уникальные имена - системные идентификаторы, по которым производится отождествление корреспондентов при обмене сообщениями между процессами и в терминах которых задается среда выполнения функций редукции. Эти имена вырабатываются функцией порождения процессов - встроенной функцией языка NEWTASK. Структура системного идентификатора определяется реализацией, это имя не имеет внешнего представления.
Для манипулирования именами процессов внутри программы в язык Fortran GNS вводится новый для Фортрана тип данных - тип TASKID. Значения этого типа представляют собой имена процессов, которые вырабатываются функцией порождения процессов.
При статической модели параллелизма системные идентификаторы процессов вырабатываются системой запуска программы и могут быть получены пользователем встроенными функциями.
Добавляется константа .NOTASKID., которая представляет собой "нулевое" значение для объектов этого типа.
Данные типа TASKID должны быть описаны в операторе TASKID, синтаксис которого аналогичен синтаксису операторов объявления типа в Фортране 77. Данные этого типа могут использоваться в операторах EQUIVALENCE, но при этом могут быть эквивалентными только данным типа TASKID. Допускается использование TASKID в качестве описателя типа подпрограммы-функции.
Использование переменных данного типа в операторах СOMMON оговаривается в инструкциях по использованию языка на конкретных установках, в них же приводятся размеры имени процесса для расчетов длин общих блоков. В реализации на базе Фортран МВК [3] допускается использование данных типа TASKID в общих блоках, их длина - одно слово (как у данных типа INTEGER).
Для данных типа TASKID определены следующие операции: операции .EQ. , .NE. и присваивание (когда операнды операций,левая и правая части операторов присваивания имеют тип TASKID).
Данные типа TASKID используются в операторах передачи/приема сообщений - SEND и RECEIVE для задания абонентов - получателя или отправителя . Такие данные могут также передаваться в качестве параметров процедурам и функциям, а также могут быть переданы другим процессам с помощью операторов передачи сообщений.
Значения типа TASKID не могут использоваться в списках ввода-вывода, так как не имеют внешнего представления.
Начальная инициализация переменных этого типа также, как и других переменных Фортрана, не предусматривается, поэтому использование данных до присваивания им значений некорректно. Присвоение начальных значений этим данным в операторах DATA не предусмотрено.
Спецификация данных типа TASKID в виде массива, структура которого совпадает с конфигурацией вычислительной системы, облегчает программирование задачи, например, может унифицировать операторы передачи данных между соседними процессами. В языке есть возможность заданием идентификатора массива данных типа TASKID указать массовую операцию для всех его элементов: в функциях порождения процессов,редукции и операциях передачи сообщений. Такая запись может ускорить выполнение программы, так как такие массовые операции могут выполняться параллельно.
Для задания массовых операций над частью массива - подмассива можно присвоить подмассиву имя оператором EQUIVALENCE, динамическое формирование структур подмассивов можно производить операторами языка Фортран МВК. Например:
       TASKID T1(100),T2(100),TM
       DIMENSION TM(100,2)
       EQUIVALENCE (TM(1,1),T1(1)),(TM(1,2),T2(1))
При статической модели параллелизма инициализация данных этого типа производится функциями преобразования номеров виртуальных процессоров в имена задач.

3. Задачи и процессы

В языке вводится дополнительный вид программных единиц - программные единицы-задачи. Программа может содержать (помимо традиционных для Фортрана программных единиц) одну или более программных единиц-задач.
Главная программная единица (main program) определяет главный и единственный - начальной процесс программы.Эта единица может иметь заголовок:
      PROGRAM n, где n - имя программы.
По Фортрану, заголовок программы может отсутствовать.
Имя программы (MAIN при его отсутствии) идентифицирует главную программную единицу программы, ссылки на него невозможны. (Конкретные реализации могут разрешать использование этого имени в операторах передачи сообщений в качестве адресата.)
При запуске начального процесса ему присваивается другое имя - системный идентификатор, по которому на него могут ссылаться другие процессы программы при передаче сообщений или при выполнении функций редукции. Это имя может быть получено любым процессом при помощи встроенной функцией MASTER без параметров. Результат функции имеет тип TASKID.
Программная единица-задача являются описанием задачи. Вычислительные процессы создаются по описанию задачи динамически и во время создания им присваиваются уникальные имена - системные идентификаторы. По одному описанию задачи может быть образовано произвольное число процессов данного класса.
Первым оператором программной единицы-задачи является оператор заголовка, имеющий вид: TASK PROGRAM n, где n - имя программной единицы-задачи.
В остальном, структура программной единицы-задачи не отличается от структуры главной программной единицы Фортрана 77. В частности, последним оператором, как обычно, является оператор END.
Задачи не могут иметь общей памяти с другими задачами, в частности, с главной, поэтому общие блоки (COMMON-блоки) задач локальны в пределах каждой задачи и программных единицах, которые в ней используются. Семантика COMMON-блоков в пределах одной задачи - традиционная.

3.1. Создание процессов.

Для создания процессов в динамической модели параллелизма используется стандартная функция NEWTASK. Обращение к этой функции производится операторами присваивания вида:
       it = NEWTASK (n, ia) , где
n
- имя программной единицы-задачи;
ia
- константа, имя переменной, элемента массива или массива целого типа; значения этого параметра определяют виртуальные номера вычислителей, на которых создаются порождаемые процессы.
it
- имя переменной, элемента массива или массива типа TASKID, куда заносятся имена (системные идентификаторы) порожденных процессов.
Функция NEWTASK создает по описанию задачи с именем n вычислительные процессы, количество которых определяется числом виртуальных номеров вычислителей. Это число равно количеству элементов массива параметра ia или равно одному для скалярного параметра.
Результатом выполнения функции NEWTASK является имя процесса или массив имен (системных идентификаторов) созданных процессов. Эти имена присваиваются переменным it.
Если n не совпадает с именем программной единицы-задачи, по которой образован текущий процесс, то оно должно быть описано. По аналогии с оператором EXTERNAL, для описания имен внешних задач вводится оператор спецификации TASK EXTERNAL, имеющий вид:
           TASK EXTERNAL n [, ni ]...
где n, ni - имена программных единиц-задач.
Имена, указанные в списке этого оператора, разрешается использовать в качестве фактических параметров процедур (в том числе в качестве параметров функций NNAME и NEWTASK) и в качестве адресатов в операторе SEND. Если в качестве таковых параметров используется имя текущей единицы - задачи, то оно также должно быть описано как внешнее.
Таким образом, передать сообщение процессу можно, идентифицируя его именем программной единицы-задачи, по которой он был образован (по имени класса), или по системному имени.
Оператор TASK EXTERNAL должен быть размещен в программе-задаче до первого исполняемого оператора.

Имена (системные идентификаторы) процессов не имеют внешнего представления, они скрыты от пользователя, их можно присваивать переменным типа TASKID. Процесс может определить собственное имя, имя процесса,породившего его, и имя главного процесса программы с помощью стандартных функций MYTASKID, РАRENT и МАSTER. Определение имен процессов по номерам виртуальных процессоров приведено в п. 7.
Созданные процессы загружаются и сразу начинают выполняться на процессорах,виртуальные (логические) номера которых заданы значениями параметра ia. Допускается использование одинаковых логических номеров для размещения процессов на одном виртуальном процессоре (для статической модели параллелизма это не так !).
Конкретное отображение виртуальных номеров процессоров на процессоры рабочей машины, способ загрузки процессов определяется реализацией, например, конструкциями языка описания конфигурации (аналогично тому, как номера каналов ввода-вывода в стандартах Фортрана не закреплены, а определяются реализацией, в частности, языком управления заданиями). Процедура создания главного процесса программы и порядок его размещения на процессоре также определяется реализацией.
При реализации статической модели параллелизма распределение процессов по процессорам производиться статически, на этапе подготовки задания. В этом случае, функции NEWTASK в программе отсутствуют и процессы запускаются при инициализации задачи. В статическом варианте имена процессов (системные идентификаторы) определяются с помощью функции GETTASKID, имеются еще ряд стандартных функций для работы в этом режиме (см. 7.).

Примеры использования функций порождения процессов
Операторы порождения будут иметь окружение программы-задачи С.
       TASK PROGRAM C
       TASK EXTERNAL A,B,READ,PRINT
       TASKID TI, TM(100),TM2(100,2)
       INTEGER K,KM(100),KM2(100,2)
       .............
       END
Инициализация процессов:
1     TI = NEWTASK(A,K)
2     TМ = NEWTASK(A,KМ)
3     TМ2 = NEWTASK(A,KМ2)
      DO 4 I=1,100
4     TМ(I) = NEWTASK(A,KМ(I))
      DO 5 I=1,100
      TМ2(I,1) = NEWTASK(A,KМ2(I,1))
5     TМ2(I,2) = NEWTASK(B,KМ2(I,2))
Операторы с метками 2 и 4 (3 и 5) производят одинаковые действия, но инициализация в форме 2 (3) предпочтительнее, так как эта запись позволяет производить инициализацию процессов параллельно.
Отсутствие в Фортране 77 аппарата вырезок из массивов не позволяет иметь такую запись для алгоритмов:
      DO 6 I=1,99,2
      TМ(I) = NEWTASK(A,KМ(I))
6     TМ(I+1) = NEWTASK(В,KМ(I+1))

или

      TМ(1) = NEWTASK(READ,KМ(1))
      TМ(100) = NEWTASK(PRINT,KМ(100))
      DO 7 I=2,99
7     TМ(I) = NEWTASK(В,KМ(I))

   В результате выполнения операторов:

      TI = NEWTASK(PRINT,1)
8     TI = NEWTASK(READ,2))
на виртуальном процессоре с номером 1 будет образован и запущен процесс PRINT, внутреннее имя которого потеряно и недоступно программе из-за выполнения оператора 8.Доступ к нему для передачи сообщений возможен только по программному имени, заказать от него прием сообщений невозможно. C процессом на втором процессоре возможен обмен сообщениями в обе стороны.
В языке определена только одна синтаксическая конструкция использования функции NEWTASK - в операторе присваивания. Тем не менее входные языки могут разрешать использование этой функции и в других контекстах, там, где употребляются переменные типа TASKID. Например, оператор:
SEND (NEWTASK(PRINT,MI)) RES
породив процесс печати, передает ему данные через RES.

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

3.2. Завершение программы и завершение процессов

Выполнение программы на языке Fortran GNS завершается в следующих случаях:
Из определения следует, что для завершения программы не требуется ожидания естественного (или авостного) завершения всех инициированных процессов программы, в частности, завершения всех обменов сообщениями между ними и выборки поступивших сообщений из почтовых ящиков. Вопрос о буферах ввода-вывода при "авосте" в главном процессе решается соглашениями ОС.
Выполнение одного процесса завершается в следующих случаях: Таким образом любой процесс может завершить выполнение всей программы выполнением стандартных процедур ABORT, FINISH; завершение процесса другими способами не прекращает выполнение программы. В частности, при выполнении оператора END в задаче, процесс завершается, ссылка на него сохраняется. Проблема почтовых ящиков завершенных процессов решаются при реализации языка.
При статической модели параллелизма работа программы завершается выполнением в одном из процессов ABORT или FINISH.
В языке нет средств для определения статуса процесса, поэтому, проблемы использования процессора,освободившегося по завершению выполняемого на нем процесса, связаны с наличием динамической загрузки процессов и должны решаться программированием синхронизирующих механизмов.

3.3. Ввод-вывод

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

4. Передача сообщений

Обмен информацией между процессами осуществляется с помощью передачи сообщений. Для этого используются операторы:
    SEND    -  послать сообщение  и
    RECEIVE -  принять сообщение.

4.1. Способы передачи сообщений

Предусмотрено три способа передачи сообщений: синхронный, асинхронный и передача без ожидания.
а. Синхронный способ
При синхронном способе передачи сообщений посылающий и принимающий процессы приостанавливают выполнение своих программ и переходят в состояние ожидания до тех пор, пока не выполнятся оба синхронных оператора SEND и RECEIVE.
Сообщения данного типа могут передаваться без использования буферов почтовых ящиков, так как передача синхронного сообщения будет производиться только при готовности абонентов к обмену и может происходить непосредственно из памяти передающего процесса в память принимающего процесса.
Процесс может посылать синхронные сообщения как отдельному процессу, так и и группе процессов. В последнем случае процесс отправитель продолжит выполнение только после получения подтверждения о выполнении соответствующих операторов RECEIVE во всех процессах - получателях. Получив сообщение, получатель группового синхронного сообщения может продолжить работу, не ожидая завершения всех остальных обменов по данному оператору SEND. Получатель синхронного сообщения может ждать его только от процесса, имя которого указано в параметре оператора RECEIVE, т.е нельзя заказать в одном операторе ожидание синхронных сообщений от нескольких процессов.
б. Асинхронный способ
При асинхронном способе передачи сообщения посылающий процесс продолжает выполнение независимо от того, выполнил ли получающий процесс оператор RECEIVE или нет.
Сразу же после выполнения оператора SEND процесс может изменить значения данных, перечисленных в списке передаваемых значений этого оператора, однако абоненту передаются те значения, которые были на момент выполнения оператора SEND.
Выполнение асинхронного оператора RECEIVE и продолжение работы процесса - получателя производиться только после поступления сообщения. Если сообщение пришло к получателю до выполнения у него оператора RECEIVE, то сообщение помещается в почтовый ящик процесса без прерывания его выполнения.Сообщения с одинаковым значением тега от одного и того же отправителя помещаются в почтовом ящике в том же порядке, как они посылались и в таком же порядке они будут выбраны операторами RECEIVE.
Сообщения, передаваемые асинхронным способом, идентифицируются именами отправителя и тегами (положительными значениями целого типа). Имя отправителя можно опускать в процессе - получателе, т.е. можно заказывать ожидание сообщений этого типа (с заданным тегом) от произвольного процесса. В этом случае отправителя можно идентифицировать при получения сообщения при помощи параметра SENDER в операторе RECEIVE.
Стандартные функции TESTMSG, TESTTAG, PROBE позволяют анализировать наличие сообщений, значения тегов и имен отправителей асинхронных сообщений в почтовом ящике процесса и ,соответственно, управлять порядком выбора поступивших сообщений.
Для организации селекции и установки режимов ожидания заданных асинхронных сообщений можно использовать также конструкции выбора (см. раздел 5.).
в. Передача без ожидания
При передаче сообщения способом "без ожидания" момент передачи сообщений (копирование данных для передачи в процессе отправителе и присваивание соответствующим переменным значений данных из принятого сообщения в процессе получателе) не определен в языке и зависит от системы интерпретации. При такой передаче работа обоих процессов (отправителя и получателя) продолжается после выполнения операторов этого вида, независимо от того, выполнилась ли фактически передача сообщения.
Так как значения данных, указанных в списке переменных оператора SEND, могут быть изменены любым следующим оператором процесса, то передаются такие значения, которые имеют эти переменные в момент фактической передачи. Оператор приема сообщений данного типа формирует заявку на прием сообщения,а переменные, перечисленные в списке не изменяются, если сообщение еще не поступило в почтовый ящик процесса на момент выполнения оператора. При поступлении сообщения, данные пересылаются из почтового ящика в память процесса (присваиваются соответствующим переменным) без прерывания его работы.
В каждым операторе обмена этого типа один из его параметров - логическая переменная FLAG служит для фиксации факта передачи сообщения. Значение этой логической переменной-флага связывается с фактом выполнения передачи данных, заданной оператором обмена для того процесса, в котором определена эта переменная. Система интерпретации присваивает флагу в процессе отправителе значение .TRUE. в момент снятия копии с данных отправителя для передачи, и флагу в процессе-получателе после присвоения этих значений переменным получателя. До выполнения оператора передачи / приема сообщения значение логической переменной - флага, связанной с этим оператором не определено.
Определить факт передачи данных и приостановить выполнение процессов до выполнения фактической передачи сообщения этого типа (для отправителя - до снятия копии с передаваемых данных, для получателя - до поступления сообщения в почтовый ящик или записи переданных данных в поле задачи) можно при помощи стандартных процедур - MSGDONE, ALLDONE, TESTFLAG.
Только установка значения флага в .TRUE. отправителю дает возможность изменять переменные, перечисленные в операторе SEND, без риска изменить передаваемые данные, для получателя - начать использовать полученные данные.Использование этих логических переменных вне операторов передачи сообщений и перечисленных выше процедур не допускается. По аналогии с асинхронным протоколом допускается ожидание асинхронных сообщений от произвольного процесса (в операторах RECEIVE можно опускать имя отправителя).
Замечание: Понятие "почтовый ящик процесса", используемое в данном описание языка, носит методический характер и служит моделью для пояснения семантических понятий аппарата передачи сообщений. Алгоритмы реализации этого аппарата зависят от особенностей вычислительной платформы и ее системного обеспечения.

4.2. Идентификация абонентов

Идентификация абонентов при организации передачи сообщений может производится по имени процесса (массиву имен) или идентификатору задачи, по описанию которой образован процесс. Есть способы безадресных (широковещательных) посылок сообщений - "всем", и приема от произвольного отправителя сообщений с заказанной "маркой" - тегом. Идентификация абонентов может быть произведена:
а) По имени процесса
Основным способом идентификации абонентов при передаче сообщений является задание имени процесса (системного идентификатора) переменными типа TASKID и стандартными функциями этого типа MYTASKID, РАRENT и МАSTER. Использование этих стандартных функций является единственным первоначальным способом сослаться из порождаемых процессов на имена порождающих процессов, так как начальный диалог между процессами возможен только на уровне порожденный-порождаемый. Путем обмена сообщениями можно организовать передачу имен процессов для организации произвольной абонентской сети.
Переменные типа TASKID - параметры операторов передачи сообщений могут:
  • ссылаться на функционирующий процесс,
  • ссылаться на завершенный процесс,
  • иметь значение .NOTASKID.,
  • быть не инициализированными.

Реакция программы на три последних случая не оговаривается в языке и определяется реализацией. Одно из решений - игнорирование оператора обмена сообщениями с такими параметрами (кроме синхронных операторов, для которых такой случай следует считать "авостом" в программе). Процесс-отправитель имеет возможность организовать дублирование передаваемых сообщений для передачи их одновременно нескольким процессам-получателем. Для этого допускается задание абонентов в параметрах оператора передачи сообщений в виде массива типа TASKID. Сообщение будет передано при этом всем процессам, на которые есть ссылки через элементы массива. Данная массовая операция предпочтительнее передачи сообщений, организованной по-элементной циклической конструкцией. Цикл предписывает порядок перебора элементов массива - абонентов передачи, а для синхронного обмена и завершение очередной передачи до посылки следующего сообщения. Массовая операция обмена может проводиться параллельно и независимо для всех заказанных абонентов. Массовые операции ассиметричны, нельзя заказать ожидание сообщения от нескольких процессов сразу. Теговая идентификация сообщений и конструкции выбора допускает некоторую вольность в указаниях об именах отправителей.

б) По имени программной единицы-задачи
Задание в операторе передачи сообщений в качестве адресата - получателя имени программной единицы-задачи означает рассылку сообщений всем процессам, образованным по описанию указанной задачи на момент выполнения оператора. Случай, когда к этому моменту не было образовано ни одного процесса по указанному образцу, можно рассматривать по аналогии с передачей сообщения процессу с "именем" - .NOTASKID. . Возможность задать в качестве адресата имя главного процесса уточняется в описаниях входных версий языка.

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

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

4.3. Операторы передачи сообщений

Операторы SEND и RECEIVE имеют вид:
   SEND (sm [,ss]...) [список]
   RECEIVE (rm [,rs]...) [список]
где
sm или rm
- спецификация сообщения - определяет адресата (процесс или процессы, которым посылается сообщение) или отправителя и способ синхронизации;
список
- список передаваемых данных имеет такой же вид, как списки в операторах ввода/вывода Фортрана 77, т.е. элементом списка может быть константа,имя переменной, переменная с индексом, имя массива или неявный цикл;
ss или rs
- дополнительная спецификация.

Вид спецификации сообщения sm и rm зависит от способа синхронизации.

а) Синхронный способ:
sm есть [TASKID =] адресат,
где адресат есть adr или ALL,
а adr - ссылка на функцию, имя переменной, элемента массива или имя массива типа TASKID или имя программной единицы-задачи.
Если adr - имя программной единицы-задачи, то сообщение посылается всем процессам программы, образованным по образцу указанной программной единицы (исключая посылающую).процедуры.
ALL - означает, что сообщение посылается всем процессам программы, образованным на момент выполнения оператора передачи сообщения, исключая процесс-отправитель.
rm есть [TASKID =] t, где t - переменная или элемент массива типа TASKID; параметр специфицирует процесс - отправитель.
Когда adr (rm) - значение типа TASKID, оно должно ссылаться на незавершенный процесс.

б) Асинхронный способ
sm есть [TAG=] ie, [TASKID =] адресат
или TASKID = адресат, [TAG =] ie
rm есть [TAG=] ie [,[TASKID =] t]
или TASKID = t, [TAG =] ie
где адресат и t определяются как rm для синхронного способа,
ie - выражение целого типа, значение которого определяет тег сообщения.

в) Способ без ожидания
sm есть [TASKID =] адресат, FLAG = l
rm есть [TASKID =] adr, FLAG = l
или [FLAG =] l
где адресат и adr определяется как и для предыдущего способа;
l - имя логической переменной. Переменная l может использоваться также в стандартных процедурах MSGDONE(l) и TESTFLAG(l) (см. п.7.). В других ситуациях ее использование не допускается.

Дополнительная спецификация
Дополнительная спецификация ss и rs , как видно из синтаксиса, является необязательной.
ss есть ERR = l
и / или SRSTAT = ios
где
l
- специфицирует метку, которой передается управление в случае ошибки при передаче сообщения;
ios
- имя переменной или элемента массива целого типа; специфицирует статус состояния (аналог спецификации IOSTAT в операторах ввода/вывода).
В результате выполнения оператора, переменной ios присваивается значение O , если не было обнаружено ошибки, и положительное значение, если обнаружена ошибка. Классификация видов ошибок определяется реализацией языка. Если спецификация SRSTAT отсутствует, то значение статуса состояния присваивается системной переменной.
Если спецификация ERR отсутствует, то в случае ошибки, задача (и вся программа) завершается выполнением стандартной процедуры ABORT.
В качестве дополнительной спецификации rs для оператора RECEIVE, помимо аналогичных спецификаций ERR и SRSTAT, можно также использовать необязательную спецификацию SENDER, т.е.
rs есть ERR = l
и / или SRSTAT = i
и / или SENDER = t
где t - переменная типа TASKID.
Cпецификацию SENDER полезно использовать, если отсутствует имя процесса-отправителя. Переменной t после выполнения оператора RECEIVE присваивается значение имени процесса-отправителя.
Замечания.
  1. Способ передачи сообщения и число элементов в списках оператора SEND и соответствующего оператора RECEIVE должны совпадать; для каждого элемента - тип, а для массивов также размерность и конфигурация должны соответствовать друг другу. Конфигурация массива - это одномерный массив целого типа, размер которого равен размерности исходного массива, а элементы равны размерам соответствующих измерений. Несоответствие структуры данных при синхронной передаче считается ошибкой в обоих процессах , при других способах передачи - ошибкой в задаче-отправителе.
  2. Если значение переменной адресата есть .NOTASKID. или ссылка на завершенный процесс, оператор обмена для этого процесса не выполняется, а спецификация SENDER получает значение .NOTASKID. .
  3. Не считается ошибкой наличие в почтовом ящике невостребованных сообщений при завершении процесса.

Использование операторов передачи сообщений

Синхронный режим передачи сообщений

По определению, синхронный режим передачи сообщений требует одновременного выполнения в процессах соответствующих операторов, что при рассогласовании работы процессов может быть источником "зависания" программы. Достоинством данного метода передачи сообщений является принципиальная возможность проводить обмен данными без использования системных буферов, что может ускорить время обмена.
Операторы передачи сообщений с пустым списком данных могут использоваться для синхронизации вычислений программы.
Для этого в процессе, управляющем синхронизацией, следует выполнить оператор: SEND(ALL), во всех процессах программы - RECEIVE (T1),где Т1 должен ссылаться на управляющую задачу. Управляющий процесс продолжиться только после выполнения во всех задачах оператора RECEIVE. Оператор SEND(А) требует синхронизации только от процессов, образованных по программе-задаче А, а SEND(ТМ) - от процессов, на которые ссылаются элементы массива ТМ. Если процессам известно, что рандеву будет требовать начальный процесс, то их синхронизирующий оператор может быть записан: RECEIVE (МАSТЕR()). Точная синтаксическая запись:
       Т1=МАSTER()
       RECEIVE (T1)
так как в параметрах операторов передачи сообщений не разрешается выражений. Реализации могут иметь расширенное толкование семантики, в частности, допускать использование функций типа TASKID в позициях переменных этого типа. Некоторые реализации могут запрещать в операторах приема сообщений неявные циклы, управляемые параметром, находящимся в этом же списке ввода. Так, в Фортране МВК запрещены такие конструкции:
       RECEIVE (<..>) N, (KM(I),I=1,N)

Асинхронный режим передачи сообщений

Использование данного способа обмена сообщениями делает программу еще менее критичной к согласованию операторов обмена сообщениями, так как процесс-отправитель продолжает работу после передачи сообщения, не дожидаясь конца фактической передачи сообщения (и даже начала, так как система интерпретации "должна" сразу же, скопировав передаваемые данные в буфер, "отпустить" процесс) . Получатель сообщений этого типа может выдавать директиву приема сообщения, только удостоверившись в наличии нужного сообщения в почтовом ящике процесса при помощи функций: TESTMSG,TESTTAG,PROBE. Выполнение оператора RECEIVE без проверки наличия сообщения в почтовом ящике процесса, по аналогии с синхронным способом обмена, приводит к задержки выполнения процесса до приема сообщения с заказанным тегом и ,возможно, с заданным именем отправителя. Но в отличие от синхронного способа, асинхронный способ позволяют проводить селекцию поступающих сообщений при помощи конструкций выбора. Пусть процесс может получать сообщения с тегом 1, но от процесса TI - скаляр целого типа, а от процесса TM(1) - массив из 100 целых чисел. Тогда,прием таких сообщений может быть запрограммированно так:
        IF (TESTTAG(1)) THEN
        SELECT MESSAGE
        CASE(1,TI)
        RECEIVE (1) K
        CASE(1,TM(1))
        RECEIVE (1) KM
        END SELECT
        END IF

или:

        SELECT MESSAGE
        CASE(1,TI)
        RECEIVE (1) K
        CASE(1,TM(1))
        RECEIVE (1) KM
        CASE DEFAULT
        GO TO 2
        END SELECT
 2      CONTINUE
Ожидание этих сообщений, то есть, по аналогии с синхронной передачей сообщений, прерывание работы процесса до получения сообщения (в данном случае любого из ожидаемого) записывается так:
        SELECT MESSAGE
        CASE(1,TI)
        RECEIVE (1) K
        CASE(1,TM(1))
        RECEIVE (1) KM
        END SELECT
Если сообщения различаются тегами, то конструкция их ожидания может иметь вид:
        SELECT MESSAGE
        CASE(1)
        RECEIVE (1) K
        CASE(2,TM(1))
        RECEIVE (2) KM
        END SELECT

Режим передачи сообщений без ожидания

Передачи сообщений этого типа рекомендуется использовать для передачи данных "впрок", заблаговременно. Если после операторов SEND / RECEIVE без ожидания, поместить операторы:
       CALL MSDONE(L),
семантика операторов будет совпадать с семантикой асинхронных операторов. Следует иметь ввиду, что при использовании операторов данного вида в цикле без использования процедур ожидания фактической передачи сообщений возможно искажение передаваемых данных; семантика функции TESTFLAG при этом будет двусмысленной.

Структура элементов списка передаваемых сообщений

Структура элементов списка передаваемых (принимаемых) сообщений, как объявлено, совпадает с списком ввода вывода операторов обмена Фортрана. Широкие возможности предоставляет аппарат неявных циклов.
Пусть имеются описания: REAL A(10),B(5,5). Тогда оператор:
       SEND(ALL)A,(B(I),I=1,5),(B(I,1),I=1,5),(B(I,I),I=1,5)
перешлет всем процессам программы следующие объекты: Этим способом можно организовать не только передачу (прием) любых вырезок их массивов, но и множества одинаковых данных, например, переслать пять копий массива В: SEND(ALL)(B,I=1,5)

5. Конструкция выбора

Конструкции выбора служат для анализа сообщений, переданных в почтовый ящик процесса асинхронным способом.Конструкция выбора позволяет, в зависимости от того, какие сообщения, передаваемые асинхронным способом, уже поступили (и, возможно, с учетом дополнительных условий), выполнить ту или иную последовательность операторов (например, содержащую оператор приема поступившего сообщения) или приостановить выполнение до поступления сообщения и затем выполнить соответствующую последовательность операторов.
Конструкция выбора имеет вид:
         SELECT MESSAGE
            [CASE(селектор)
             блок]...
            [CASE DEFAULT
             блок]
          END SELECT
где
селектор есть [TAG=] ie
и / или [TASKID=] t
и / или COND= le
где
ie
- выражение целого типа (тег);
t
- переменная или элемент массива типа TASKID;
le
- логическое выражение;
блок
- это последовательность выполняемых операторов, которая должна удовлетворять тем же требованиям, что и блоки конструкции IF-ENDIF в Фортране 77, а именно: передача управления внутрь блока извне запрещена, однако внутри блока переходы допускаются; разрешается выход из конструкции, допускаются операторы CALL и обращения к функциям; если блок содержит управляющую конструкцию IF-ENDIF или SELECT MESSAGE - END SELECT , то эта конструкция должна целиком принадлежать блоку. На оператор CASE нельзя передавать управление. Переход на оператор END SELECT разрешен только внутри конструкции.
Если значение логического выражения хотя бы в одной COND-спецификации - .TRUE. и сообщение, специфицированное в том же операторе CASE, поступило, то выполняется соответствующий блок (если таких операторов CASE несколько, то выполняется один из блоков по усмотрению системы интерпретации, для которых выполняются эти условия). Если же нет оператора CASE, удовлетворяющего таким условиям, то выполняется блок, следующий после CASE DEFAULT.
Если в операторе CASE отсутствует COND-спецификация, полагается что COND=.TRUE.
Если оператор CASE DEFAULT отсутствует и значения всех логических выражений - .FALSE., то это ошибка периода выполнения. Если (при отсутствии блока CASE DEFAULT) для всех тех логических выражений, значение которых - .TRUE., соответствующее сообщение еще не поступило, то процесс переходит в состояние ожидания.

6. Стандартные процедуры

Список стандартных процедур, которые введены в язык для реализации механизма управления работой процессов, приведен в таблице . В динамической модели параллелизма процедура NEWTASK порождает вычислительный процесс и вырабатывает его имя. С помощью стандартных функций MYTASKID(), MASTER(), РАRENT() можно получить имя процесса, вызвавшего функцию (имя текущего процесса), имя начального процесса или имя процесса, породившего текущий, соответственно.
В статическом режиме, т.е. при отсутствии вызова функции NEWTASK, результат выполнения функций PARENT() и MASTER() - константа .NOTASKID.
Функция GETTASKID (proc) возвращает имя процесса , расположенного на виртуальном процессоре с номером proc. Тип результата функции - TASKID.
Целая функция NNAME (name) возвращает количество процессов, созданных из программной единицы-подзадачи с именем name. Аргумент функции должен быть указан в операторе TASK EXTERNAL. Если он равен '*' , то возвращается число всех виртуальных процессоров программы.
Целая функция NVIRPR (name,array,array_lengr) возвращает количество процессов, созданных из программной единицы-подзадачи с именем name. Этот аргумент функции должен быть указан в операторе TASK EXTERNAL. Если он равен '*' , то возвращается число всех виртуальных процессоров программы. Функция также заносит в массив array (идентификатор массива или переменная с индексом) номера виртуальных процессоров, на которых образованы процессы с именем name или всех процессоров программы (для name = '*'). Значение параметра array_lengr задает целое число элементов массива array, куда следует записать номера процессоров. Если параметр больше, чем число записываемых процессоров, то значение функции - фактическое число процессоров, а в массив заносятся только эти номера. Если параметр array_lengr меньше, чем число записываемых процессоров, то значение функции - фактическое число процессоров, умноженное на -1, а в массив заносятся только заданное число процессоров. Данная функция отличается от функции NNAME наличием бокового эффекта.
Целая функция NTASKS () возвращает количество всех процессов (число виртуальных процессоров) в выполняемой программе.
Целая функция MYVP () возвращает номер виртуального процессора для процесса, вызвавшего эту функцию.
Результат функции TESTMSG(i,t) - .TRUE. или .FALSE. в зависимости от того, находится ли в почтовом ящике задачи, вызвавшей функцию, сообщение от задачи с именем t с тегом, равным i.
Результат функции TESTTAG(i) - .TRUE. или .FALSE. в зависимости от того, находится ли в почтовом ящике задачи сообщение с тегом, равным i.
Функция PROBE() последовательно выдает значение тега тех сообщений, которые уже содержатся в почтовом ящике. Если функция вызывается несколько раз, сканируется почтовый ящик; когда почтовый ящик пуст (или перебрано все содержимое ящика) - выдается признак -1. (Из этого следует рекомендация не использовать эту константу в качестве тега.) При реализации возможно уточнение семантики функции, например, определения правила начальной установки указателя функции, порядка перебора содержимого ящика.

Реализация данной функции в языке Фортран МВК.

Функция PROBE работает с очередью асинхронных сообщений, поступивших в почтовый ящик процесса. Каждый элемент очереди идентифицирован тегом сообщения и TASKID-ом процесса-отправителя. Функция использует внутренний, недоступный пользователю, указатель на текущий элемент очереди. Функция PROBE возвращает тег текущего элемента очереди и сдвигает указатель на следующий элемент очереди. Если очередь исчерпана (или была пуста), то функция возвращает значение -1. Указатель устанавливается на начало очереди в следующих случаях:
Эти функции можно использовать для анализа почтового ящика при асинхронном способе передачи сообщения без использования конструкций выбора.
Cледующие три процедуры предназначены для режима без ожидания. Процедура MSGDONE(l) организует режим ожидания (прерывание выполнения процесса) до тех пор, пока передача сообщения с FLAG = l не будет фактически выполнена.
Процедура ALLDONE() организует ожидание фактического выполнения передачи всех сообщений, которые передаются способом без ожидания.
Функция TESTFLAG(l) выдает значение .TRUE. или .FALSE. в зависимости от того, выполнена ли фактически передача сообщения с FLAG = l. Использование функций с параметром FLAG = l корректно только после выполнения операторов SEND / RECEIVE с этим флагом.
Процедура SETNAME(c) присваивает имя (строку символов - с) текущему процессу, а функция MYNAME() выдает это имя или символ ", если имя не присваивалось. Эти две функции предназначаются для отладки.
Процедура ABORT( ) - вызывает завершение всей программы.
Процедура FINISH( ) - вызывает завершение всей программы.


Имя процедуры Число аргументов Тип или класс аргументов Тип результата
1 2
NEWTASK 2 n i t
MYTASKID 0 - - t
MASTER 0 - - t
PARENT 0 - - t
GETTASKID 1 i - t
NNAME 1 n - i
NTASKS 0 - - i
MYVP 0 - - i
TESTTAG 1 i - l
TESTMSG 2 i t l
TESTFLAG 1 l - l
PROBE 0 - - i
MSGDONE 1 l - -
ALLDONE 0 - - -
ABORT 0 - - -
FINISH 0 - - -
SETNAME 1 c - -
MYNAME 0 - - c


Примечание
В таблице используются следующие обозначения:
t - TASKID l - LOGICAL n - имя программной единицы
i - INTEGER c - CHARACTER

Процедура выдачи реального времени

       SYSTEM_CLOCK (COUNT, COUNT_RATE, COUNT_MAX)
Для выдачи информации из часов реального времени имеется подпрограмма SYSTEM_CLOCK. Процедура имеет три аргумента, все три аргумента - выходные и они целого типа.
Первому аргументу (COUNT) присваивается текущее значение процессорных часов. Значение процессорных часов увеличивается на единицу для каждого такта часов, пока не достигнет максимального значения (COUNT_MAX) и устанавливается в нуль для следующего такта (т.е. значение находится в интервале от 0 до COUNT_MAX).
Второму аргументу (COUNT_RATE) присваивается значение равное количеству тактов процессорного времени в секунду, третьему (COUNT_MAX) - максимальное значение, которого может достигнуть COUNT.

7. Функции редукции

В язык введены функции редукции с двумя параметрами, реализующие массовые поэлементные операции. Операция редукции выполняются в среде процессов, на которые есть ссылки из одного из параметров функции данного типа - массива типа TASKID. Все эти процессы должен вызывать одинаковую функцию (и в которых указана одинаковая общая среда выполнения), которые выполняется синхронно, и результаты возвращаются каждому процессу, содержащему обращение. Редукция применяется для всех переменных, заданных другим параметром - аргументом операции (для каждого элемента массива отдельно, если параметр - массив) по всем процессам, указанным в обращении. При этом, типы,размерность и конфигурация параметров-массивов (аргументов операции) во всех процессах должны совпадать. Результат выполнения функции, рассылаемый всем процессам среды, имеет тип, размерность и конфигурацию аргумента.
Процедура TSORT(t), входящая в состав функции редукции, где t - массив типа TASKID, служит для указания (не обязательного) о предстоящих выполнениях функций редукции в среде процессов, на которые ссылаются элементы массива t. Используется для оптимизации межпроцессорных обменов при выполнении операций редукции.

Перечень функций редукции


Имя процедуры Тип аргументов Тип результата Назначение
1 2
PMAXVAL r/d/i t r/d/i Максимальное значение
PMINVAL r/d/i t r/d/i Минимальное значение
PALL l t l Конъюнкция элементов массива
PANY l t l Дизъюнкция элементов массива
PCOUNT l t i Число элементов .TRUE.
PPRODUCT r/d/i t r/d/i Произведение элементов массива
PSUM r/d/i t r/d/i Сумма элементов массива
TSORT t - - Упорядочение массивов среды

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

Примечание
В таблице используются те же обозначения, что и в таблице 1., а r обозначает REAL.

7.1. Использование функций редукции

Если из порожденных оператором: TI = NEWTASK(G,MI) процессов задачи G один из них, с наименьшим значением S, на некотором этапе работы должен исключаться из дальнейшей работы - завершаться авостом (изменять алгоритм счета, передавать свои результаты на печать и т.д.), то если:
то с помощью функций редукции можно скорректировать работу процессов оператором:
      IF(S .EQ. PMINVAL (S,LTI)) ABORT() .
Из определения функций редукции не следует требование выполнение редукции для процессов одного класса (образованных по одному описанию задачи).
Так, функции суммирования, одновременно выполненные в разных процессах в среде из двух процессов:
1        A   = PSUM(B,T)
2        A1  =  PSUM(B1,T1)
поэлементно просуммируют массивы В,В1 и результаты занесут в массивы А.А1, т.е. А(i) = A1(i) = B(i)+B1(i) , если:

7.2. Использование статической модели параллелизма

Пусть, необходимо написать параллельную программу суммирования элементов массива, которая сама настраивалась на число процессоров, выделяемых ей для работы. Программа суммирования может быть записана так:
     TASK PROGRAM SUM
C Параметризация максимальной длины суммируемого массива и тега
     PARAMETR (NA=100000,NT=13)
     REAL A(NA)
     TASKID T
C Ожидание вызова, N - длина массива, подлежащая суммированию
C Фиксация в T имени вызывающего процесса, асинхронно
1    RECEIVE (TAG=NT,SENDER=T) N
C Прием суммируемого массива по синхронному протоколу
     RECEIVE (TASKID=T) (NA(I),I=1,N)
     S = 0.0
     DO I = 1,N
       S = S + NA(I)
     ENDDO
C Отсылка результата в вызывающий процесс, асинхронно
     SEND (TAG=NT+1,TASKID=T) S
C  Переход в начало для многократного суммирования
     GO TO 1
     END
Обращение к процессу суммирования может многократно производится по имени процесса SUM из любого процесса программы последовательностью операторов:
     SEND (SUM,TAG=NT) N
     SEND (SUM) (A(I),I=1,N)
     RECEIVE (TAG=NT+1) S
Естественно, значение NT должны быть согласовано с значением тега в программе SUM. В вызывающем процессе должны находиться описания A и SUM ( TASK EXTERNAL SUM), определено значение N.
Модификация программы для параллельного суммирования с коэффициентом распараллеливания, равным числу инициализированных при задании конфигурации процессов класса SUM, может быть проведена так:
В вызывающем процессе описывается массив MCPU целого типа с длиной, равной максимальному числу виртуальных процессоров, на которых возможна инициализация процессов класса SUM.
Перед обращением определяется число процессов SUM и квота элементов массива суммирования для каждого процесса SUM (общая его длина принимается за N).
     NSUM = NVIRPR(SUM,MCPU,NNAME(SUM))
C  Вычисление квоты для  суммируемых сегментов массива
     N1 = N/NSUM
     N2 = N1
     SSUM = 0.0
     DO J=1,NSUM
C Последняя длина может быть длиннее N1, если N не кратно NSUM
     IF (J.EQ.NSUM) N2 = N-(J-1)*N1
     SEND (TASKID=GETTASKID(MCPU(J)),TAG=NT) N2
     SEND (TASKID=GETTASKID(MCPU(J)))(A(I),I=1+J*N1-N1,1+J*N1-N1+N2)
     SELECT MASSAGE
       CASE (TAG=NT+1)
         RECEIVE (TAG=NT+1) S
         SSUM = SSUM+S
     END SELECT
     ENDDO
Манипулируя только числом порожденных процессов SUM при задании конфигурации можно, не изменяя программы, при ее исполнении менять степень распараллеливания суммирования. В данном примере функции распределения работ были отданы вызывающей программе.
Для управления параллельными работами в самой процедуре суммирования (или иной распараллеливаемой процедуре) можно использовать другие приемы программирования.
Пусть, вызывающая программа отдает массив(ы) для обработки одной процедуре (процессу), которая сама будет распараллеливать процесс вычислений по своему алгоритму, с учетом наличия в вычислительной среде однородных процессов. Следующий оператор и его окружение в вызывающей программе очевиден.
    NSUM = NVIRPR(SUM,MCPU,NNAME(SUM))
Далее, процесс отправляет первому (возможно единственному) массив для обработки и принимает результаты.
     SEND (TASKID=GETTASKID(MCPU(1)),TAG=NT) N
     SEND (TASKID=GETTASKID(MCPU(1)))(A(I),I=1,N)
     RECEIVE (TAG=NT+1) S
Теперь необходима модификация описания процедуры SUM.
     TASK PROGRAM SUM
     PARAMETR (NA=100000,NT=13,MAXCPU(100))
     REAL A(NA)
     TASKID T
     INTEGER MCPU(MAXCPU)
     NSUM = NVIRPR(SUM,MCPU,NNAME(SUM))
1    IF (MCPU(1).NQ.MYVR()) GO TO 2
     RECEIVE (TAG=NT,SENDER=T) N
     RECEIVE (TASKID=T) (NA(I),I=1,N)
     N1 = N/NSUM
     N2 = N1
     SSUM = 0.0
     DO J=2,NSUM
     IF (J.EQ.NSUM) N2 = N-(J-1)*N1
     SEND (TASKID=GETTASKID(MCPU(J)),TAG=NT) N2
     SEND (TASKID=GETTASKID(MCPU(J)))(A(I),I=1+J*N1-N1,1+J*N1-N1+N2)
     SELECT MASSAGE
       CASE (TAG=NT+1)
         RECEIVE (TAG=NT+1) S
         SSUM = SSUM+S
     END SELECT
     ENDDO
     DO I = 1,N1
       SSUM = SSUM + NA(I)
     ENDDO
     SEND (TAG=NT+1,TASKID=T) SSUM
     GO TO 1
2    RECEIVE (TAG=NT,SENDER=T) N
     RECEIVE (TASKID=T) (NA(I),I=1,N)
     S = 0.0
     DO I = 1,N
       S = S + NA(I)
     ENDDO
     SEND (TAG=NT+1,TASKID=T) S
     GO TO 1
     END

8.Литература

  1. Система программирования Фортран GNS. Описание языка. Отчет Института прикладной математики им. М.В.Келдыша РАН. Москва, 1995, 20 с.
  2. Thole C.-A. Proposal for a Fortran Syntax Specification for distributed memory architectures. Version 1.0, April 30, 1990
  3. Фортран-МВК, Отчет ИПМ N ______ , 1995 г.