Механизмы параллельных вычислений в Windows. Разработка справочной системы
Рефераты >> Программирование и компьютеры >> Механизмы параллельных вычислений в Windows. Разработка справочной системы

Элемент кортежа в функции in считается формальным, если перед ним стоит определитель типа. Если используется переменная без определителя типа, то берется ее значение и элемент рассматривается как фактический параметр. Например, во фрагменте программы

int i = 5;

in( "P", i, FALSE ); функции in, в отличие от предыдущего примера, соответствует только кортеж ("P", 5, FALSE).

Если переменная описана до вызова функции и ее надо использовать как формальный элемент кортежа, можно использовать ключевое слово formal или знак '?'. Например, во фрагменте программы

j = 15;

in( "P", formal i, j );

последнюю строку можно заменить и на оператор in("P", ?i, j). В этом примере функции in будет соответствовать, например, кортеж ("P", 6, 15), но не ("P", 6, 12). Конечно же, формальными могут быть и несколько элементов кортежа одновременно:

in ( "Add_If", int i, bool b);

Если после такого вызова функции в пространстве кортежей будет найден кортеж ("Add_If", 100, TRUE), то переменной i присвоится значение 100, а переменной b - значение TRUE.

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

Функция EVAL похожа на функцию out. Разница заключается лишь в том, что дополнительным элементом кортежа у eval является функция пользователя. Для вычисления значения этой функции система Linda порождает параллельный процесс, на основе работы которого она формирует кортеж и помещает его в пространство кортежей. Например,

eval ("hello", funct( z ), TRUE, 3.1415);

При обработке данного вызова система создаст новый процесс для вычисления функции funct( z ). Когда процесс закончится и будет получено значение w = funct( z ), в пространство кортежей будет добавлен кортеж ("hello", w, TRUE, 3.1415). Функция, вызвавшая eval, не ожидает завершения порожденного параллельного процесса и продолжает свою работу дальше. Следует отметить и то, что пользователь не может явно управлять размещением порожденных параллельных процессов на доступных ему процессорных устройствах - это Linda делает самостоятельно.

Параллельная программа в системе Linda считается завершенной, если все порожденные процессы завершились или все они заблокированы функциями in и read.

По сути дела, описание системы закончено, и теперь можно привести несколько небольших примеров. Мы уже говорили о том, что параллельные процессы в системе Linda напрямую друг с другом не общаются, своего уникального номера-идентификатора не имеют и общего числа параллельно работающих процессов-соседей, вообще говоря, не знают. Однако если у пользователя есть в этом необходимость, то такую ситуацию очень просто смоделировать. Программа в самом начале вызывает функцию out:

out( "Next", 1);

Этот кортеж будет играть роль "эстафетной палочки", передаваемой от процесса процессу: каждый порождаемый параллельный процесс первым делом выполнит следующую последовательность:

in( "Next", formal My_Id);

out( "Next", My_Id+1);

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

read( "Next", formal Num_Processes);

Теперь рассмотрим возможную схему организации программы для перемножения С=A*B двух квадратных матриц размера N*N. Инициализирующий процесс использует функцию out и помещает в пространство кортежей исходные строки матрицы A и столбцы матрицы B:

out( "A",1, <1-я строка A>);

out( "A",2, <2-я строка A>);

.

out( "B",1, <1-й столбец B>);

out( "B",2, <2-й столбец B>);

.

Для порождения Nproc идентичных параллельных процессов можно воспользоваться следующим фрагментом:

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

eval( "ParProc", get_elem_result() );

Входные данные готовы, и нахождение всех N2 элементов Cij результирующей матрицы можно выполнять в любом порядке. Главное - это распределить работу между процессами, для чего процесс, инициирующий вычисления, в пространство помещает следующий кортеж:

out( "NextElementCij", 1);

Второй элемент данного кортежа всегда будет показывать, какой из N2 элементов Cij предстоит вычислить следующим. Базовый вычислительный блок функции get_elem_result() будет содержать следующий фрагмент:

in( "NextElementCij", formal NextElement);

if( NextElement < N*N )

out("NextElementCij ", NextElement + 1);

Nrow = (NextElement - 1) / N + 1;

Ncol = (NextElement - 1) % N + 1;

В результате выполнения данного фрагмента для элемента с номером NextElement процесс определит его местоположение в результирующей матрице: номер строки Nrow и столбца Ncol. Заметим, что если вычисляется последний элемент, то кортеж с именем "NextElementCij" в пространство не возвращается. Когда в конце работы программы процессы обратятся к этому кортежу, они будут заблокированы, что не помешает нормальному завершению программы. И, наконец, для вычисления элемента Cij каждый процесс get_elem_result выполнит следующий фрагмент:

read( "A", Nrow, formal row);

read( "B", Ncol, formal col);

out( "result", Nrow, Ncol, DotProduct(row,col) );

где DotProduct это функция, реализующая скалярное произведение. Таким образом, каждый элемент произведения окажется в отдельном кортеже в пространстве кортежей. Завершающий процесс соберет результат, поместив их в соответствующие элементы матрицы C:

for ( irow = 0; irow < N; irow++)

for ( icol = 0; icol < N; icol++)

in( "result", irow + 1, icol + 1, formal C[irow][icol]);

Не имея в системе Linda никаких явных средств для синхронизации процессов, совсем не сложно их смоделировать самому. Предположим, что в некоторой точке нужно выполнить барьерную синхронизацию N процессов. Какой-то один процесс, например, стартовый, заранее помещает в пространство кортеж ("ForBarrier", N). Подходя к точке синхронизации, каждый процесс выполняет следующий фрагмент, который и будет выполнять функции барьера:

in( "ForBarrier", formal Bar);

Bar = Bar - 1;

if( Bar != 0 ) {

out( "ForBarrier", Bar);

read( "Barrier" );


Страница: