Системы, управляемые потоком данных. Язык "Dataflow Graph Language" — страница 4

  • Просмотров 1267
  • Скачиваний 146
  • Размер файла 49
    Кб

процесса и имеет расширение frm (можно воспользоваться файлом Process.frm). В нашем случае имеем три файла: Manager.frm, Worker.frm и Summer.frm. В каждом файле есть процедура, имя которой заканчивается на Body. Внутри нее записывается тело процесса. 10 PROCEDURE ManagerBody; 11 VAR 12 Task : RECORD N:cardinal; a,b:real; END; 13 i,WrkId : cardinal; 14 CONST 15 N : cardinal = 10; 16 BEGIN 17 exportNumIter[0].Send (N, SizeOf(N)); 18 Task.N := 10*N; 19 Task.b := 0; 20 FOR i := 1 TO N DO BEGIN 21 Task.a := Task.b; 22 Task.b := i * 1.0 / N; 23 importDemandList.Receive (WrkId, SizeOf(WrkId)); 24 exportWorker[WrkId].Send (Task,

SizeOf(Task)); 25 END; 26 Task.N := 0; 27 FOR i := 1 TO exportWorker.NChannels DO 28 exportWorker[i-1].Send (Task, SizeOf(Task)); 29 END; Файл Manager.frm : тело процесса Manager Переменная Task описывает задание для рабочего процесса: a,b - границы, N - число интервалов. Константа N, описанная в строке 15, равна числу разбиений отрезка [0;1]. В начале работы посылаем процессу Summer число разбиений N (строка 17) . В строке 23 ждем запроса от одного из рабочих процессов. Запрос представляет собой идентификатор

запрашивающего процесса. Получив запрос, отсылаем очередное задание соответствующему рабочему (строка 24). После того, как задания распределены, нужно сообщить об этом всем рабочим процессам. Для этого служат строки 26-28: по всем каналам порта exportWorker посылаем задание с нулевым числом интервалов - сигнал о завершении работы. 30 PROCEDURE WorkerBody; 31 VAR 32 Task : RECORD N:word; a,b:real; END; 33 S : real; 34 i : word; 35 FUNCTION f(x:real):real; 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: dglc Pi.dgl Компилятор, если нет ошибок, сгенерирует следующие файлы: Pi.dpr, Manager.pas, Worker.pas,