Резиденты

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

Рассмотрим пример использования резидента R1.A, расположенный в каталоге Concur.

Пример 1. Определение резидента.

-------------------------------------------
-- An example of Actor Prolog program.   --
-- (c) 2002, Alexei A. Morozov, IRE RAS. --
-- A resident.                           --
-------------------------------------------
project: (('R1'))
-------------------------------------------

Экземпляр класса 'R1' содержит два процесса - p1 и p2. Процесс p2 наблюдает за процессом p1 с помощью резидента. Определение резидента осуществляется с помощью инфикса "??". Целевой процесс помещается перед инфиксом, а предикат, который необходимо доказывать в целевом процессе - после. Обратите внимание, что определение резидента задано в качестве начального значения некоторого слота data процесса p2. Это означает, что слот data будет использоваться в качестве общей переменной, через которую резидент будет посылать своему владельцу собранную информацию. Считается, что резидент посылает данные через некоторый защищающий порт.

class 'R1':
--
p1      = (('Target'));
p2      = (('Observer',
                data= p1 ?? f(1,2,3,4)
                ));
--
[
goal.
]
-------------------------------------------

Класс 'Target' является потомком предопределённого класса 'Alpha', в котором реализованы арифметические функции. Одна из них, арифметическое сложение, использована в определении предиката f, который будет доказывать резидент. Предикат f имитирует функцию, возвращающую некоторые значения. Для этого в заголовке соответствующего предложения использован ограничитель "=". Предикаты, вызываемые резидентами, всегда должны оформляться как функции. Обратите внимание, что функция f недетерминированная, и в результате её доказательства будут получены три решения.

class 'Target' specializing 'Alpha':
[
goal.
--
f(_,_,C,D)= C + D.
f(A,B,C,D)= A + B + C + D.
f(A,B,_,_)= A + B.
]
-------------------------------------------

Класс 'Observer' печатает в текстовом окне информацию, приходящую через слот data.

class 'Observer' specializing 'Report':
--
data;
--
[
goal:-
        writeln("Received data:"),
        set_color('Blue'),
        writeln(data),
        set_color('Black').
]
-------------------------------------------

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



Рис. 1.1. Графическое изображение резидента.

Вот что программа напечатает на экране:



Рис. 1.2. Работа резидента.

Первый раз, когда процесс p2 напечатал несвязаннную переменную, данные от резидента ещё не поступили. Как только процесс p2 получил список значений функции f процесса p1, он осуществил повторную печать. Обратите внимание, что резидент упорядочил список посылаемых значений. Кроме этого, в соответствии с семантикой Акторного Пролога резиденты удаляют из списка решений все повторные элементы.

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

Рассмотрим пример R3.A, расположенный в каталоге Concur.

Пример 2. Резидент, наблюдающий за тремя процессами.

-------------------------------------------
-- An example of Actor Prolog program.   --
-- (c) 2002, Alexei A. Morozov, IRE RAS. --
-- A resident inspecting a set of target --
-- processes.                            --
-------------------------------------------
project: (('Observer'))
-------------------------------------------
class 'Observer' specializing 'Report':
--
w1      = (('P1'));
w2      = (('P2'));
w3      = (('P3'));
--
target  = [w1,w2,w3];
result  = target ?? function(1,2,3);
[
goal:-
        writeln("Collected data:"),
        set_color('Blue'),
        writeln(result),
        set_color('Black').
]
-------------------------------------------
class 'P1' specializing 'Alpha':
[
goal.
--
function(_,_,_)= "From P1".
function(A,_,_)= A * 100.
]
-------------------------------------------
class 'P2' specializing 'Alpha':
[
goal.
--
function(_,_,_)= "From P2".
function(_,B,_)= B * 200.
]
-------------------------------------------
class 'P3' specializing 'Alpha':
[
goal.
--
function(_,_,_)= "From P3".
function(_,_,C)= C * 300.
]
-------------------------------------------

Рекомендуемое графическое обозначение для резидентов с несколькими целевыми процессами:



Рис. 2.1. Резидент с тремя целевыми процессами.

Вот что программа напечатает на экране:



Рис. 2.2. Сбор информации о нескольких целевых процессах.

Резидент подставил вместо целевых процессов в списке [w1,w2,w3] соответствующие списки значений функции function и послал его своему владельцу - экземпляру класса 'Observer'.

Резиденты реагируют не только на изменение состояния целевых процессов. Любое изменение списка целевых процессов или аргументов функции резидента также приводит к активизации резидента и повторному сбору информации в целевых мирах.

Логический статус механизма резидентов в Акторном Прологе зависит от того, как именно они используются в программе. Аккуратное использование резидентов позволяет создавать параллельные программы, реализующие полный перебор и при этом обладающие строгой теоретико-модельной семантикой.

Оглавление