36 BEGIN
37 Result := 4 / (1 + x*x);
38 END;
39 BEGIN
40 exportDemand[0].Send (FloLib.CopyNumber, SizeOf(cardinal));
41 WHILE (true) DO WITH Task DO BEGIN
42 importArg.Receive (Task, SizeOf(Task));
43 IF (Task.N = 0) THEN EXIT;
44 h := (b-a)/N;
45 S := 0;
46 FOR i := 1 TO N DO
47 S := S + f(a+(i-0.5)*h);
48 S := h*S;
49 exportPartSum[0].Send (S, SizeOf(S));
50 exportDemand[0].Send (FloLib.CopyNumber,SizeOf(cardinal));
51 END;
52 END;
Файл Worker.frm : телопроцесса Worker
Бесконечный цикл 41-51 обеспечивает работу процесса до получения сигнала завершения от распределителя работ Manager.
В строке 42 ждем очередное задание Task. Если число интервалов в задании равно 0, то завершаем работу. В противном случае вычисляем частичную сумму на интервале (Task.a; Task.b) и отсылаем ее суммирующему процессу (строки 44-49). В строке 50 обращаемся к распределителю работ за очередным заданием.
53 PROCEDURE SummerBody;
54 VAR
55 N, i : cardinal;
56 F : TextFile;
57 TotalSum, S : real;
58 BEGIN
59 importNumIter.Receive (N, SizeOf(N));
60 TotalSum := 0;
61 FOR i := 1 TO N DO BEGIN
62 importPartSum.Receive (S, SizeOf(S));
63 TotalSum := TotalSum + S;
64 END;
65 AssignFile (F, ‘Pi.result’);
66 Rewrite (F);
67 WriteLn (F, ‘Pi = ’, TotalSum);
68 CloseFile (F);
69 END;
Файл Summer.frm : телопроцесса Summer
В строках 61-64 собираются частичные суммы от всех рабочих процессов и суммируются в переменной TotalSum. Число частичных сумм записываем в переменну N из порта importNumIter (строка 59).
Компиляция узловых процессов
После того, как созданы шаблоны, нужно получить из них файлы, пригодные для компиляции. Для этого используется компилятор с языка DGL:
dglcPi.dgl
Компилятор, если нет ошибок, сгенерирует следующие файлы: Pi.dpr, Manager.pas, Worker.pas, Summer.pas.
Загрузка и выполнение программы
Сначала на компьютерах сети нужно запустить программу-монитор. Перепишем откомпилироанные файлы и файл Pi.dgl с текстом графа потока данных на языке DGL в один каталог и запустим диспетчер, указав Pi.dgl в качестве параметра. После окончания работы диспетчера должен появится файл Pi.result, в котором записано приближенное значение числа Pi.
Приложение А
Синтаксис языка DGL
DGL = ["DATAFLOW GRAPH" [identifier] ";"]
{Definitions}
{ProcessDecl}
Definitions = identifier "=" ConstExpr
ProcessDecl = "PROCESS" identifier ["AT" path]
["[" NumCopies "]" ]
{"EXPORT:"{ExportDecl} |
"IMPORT:"{ImportDecl}
}
"END"
ExportDecl = identifier ["[" NumCopies "]"]
"-->"
identifier ["[" Expression "]"]
":"
identifier ";"
ImportDecl = identifier ";"
NumCopies = ConstExpr
ConstExpr = Expression
Expression = Term [AddOp Term]
Term = Fact [MulOp Fact]
Fact = number | identifier | "(" Expression ")"
AddOp = "+" | "-"
MulOp = "*" | "/"
Замечания:
number - целое положительное число
все операции языка целочисленные
значение выражения NumCopies должно быть больше нуля, в противном случае оно заменяется на число 1
в выражениях можно использовать следующие переменные: с - номер текущего канала, р - номер текущей копии процесса
Список литературы
[1] Роберт Бэб, «Программирование на параллельных вычислительных системах» - Москва: Мир, 1991
[2] А.И.Водяхо, «Высокопроизводительные системы обработки данных» - Москва:Высшая школа, 1997