OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Вторник, 15 Октябрь, 2019 12:34

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 15 ] 
Автор Сообщение
СообщениеДобавлено: Пятница, 23 Июнь, 2006 08:22 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
(модератор 31.01.2012): загружено в коллекцию как omcBus

В результате нехитрых комбинаций соображений по поводу обобщенной транспортной шины передачи сообщений между объектами родилась идея передавать сообщения не только между объектами, но и между модулями. Модули в данном случае отличаются от объектов тем, что у модулей всегда есть своё уникальное имя. Естественно было бы посылать сообщения модулю зная только лишь его символьное имя.

Интерфейс шины межмодульной передачи сообщений можно определить, например, так:
Код:
DEFINITION Bus;

  TYPE
    Message = ABSTRACT RECORD END;

    HandleBusMessage = PROCEDURE (VAR msg: Message);

  PROCEDURE Send (IN destination: ARRAY OF CHAR; VAR msg: Message; OUT ok: BOOLEAN);

END Bus.

Каждый модуль заинтересованный в возможности принятия и обработки таких сообщений должен экспортировать процедуру типа HandleBusMessage с именем "HandleBusMessage". В таком случае любой кто захочет, сможет передать этому модулю сообщение Message зная только лишь символьное имя модуля получателя.

PROCEDURE Send (IN destination: ARRAY OF CHAR; VAR msg: Message; OUT ok: BOOLEAN);
Отправка сообщения модулю.

Предусловие:
destination - имя модуля получателя;
msg - сообщение для этого модуля;

Постусловие:
ok = TRUE если модуль destination был найден и была найдена и вызвана экспортированная им процедура HandleBusMessage. В противном случае ok = FALSE (либо такой модуль не найден, либо он не экспортирует нужной процедуры).


Пример использования транспортной шины межмодульной передачи сообщений:
Код:
MODULE TestBus;

  IMPORT Log, Bus;

  TYPE
    HelloMsg = RECORD (Bus.Message) END;
 
  PROCEDURE HandleBusMessage* (VAR msg: Bus.Message);
  BEGIN
    WITH msg: HelloMsg DO
      Log.String("HelloMsg received!!!"); Log.Ln
    ELSE
    END
  END HandleBusMessage;

  PROCEDURE Test*; (* (!)TestBus.Test *)
    VAR msg: HelloMsg; ok: BOOLEAN;
  BEGIN
    Bus.Send("TestBus", msg, ok) (* Отправка сообщения msg модулю "TestBus", т.е. самому себе *)
  END Test;

END TestBus.

А вот и полная реализация модуля Bus средствами Meta-программирования:
Код:
MODULE Bus;

  IMPORT Meta;

  TYPE
    Message* = ABSTRACT RECORD END;
   
    HandleBusMessage* = PROCEDURE (VAR msg: Message);

  PROCEDURE Send* (IN destination: ARRAY OF CHAR; VAR msg: Message; OUT ok: BOOLEAN);
    VAR m, p: Meta.Item;
    r: RECORD (Meta.Value) h: HandleBusMessage END;
  BEGIN ok := FALSE;
    Meta.Lookup(destination$, m);
    IF m.obj = Meta.modObj THEN
      m.Lookup("HandleBusMessage", p);
      IF p.obj = Meta.procObj THEN
        p.GetVal(r, ok);
        IF ok THEN r.h(msg) END
      END
    END
  END Send;

END Bus.

Для чего это можно использовать, наверное, и так понятно. Например, пусть есть модули А и В. Модуль В импортирует модуль А и вызывает его процедуры. Пусть теперь появился модуль А2 с таким же интерфейсом как и А, и нам вдруг захотелось, чтобы модуль В теперь работал с модулем А2. Поможет только перекомпиляция модуля В. Но ежели модуль В будет общаться с модулем А только зная его символьное имя, то надо будет просто заменить это имя на "А2", динамически, не останавливая работу. Кстати, после такого переключения, модуль А даже можно будет выгрузить из системы.

P. S. Следующим логическим шагом конечно же будет реализация remoting-шины, позволяющей посылать сообщения модулям запущенным на других компьютерах, т.е. по адресу: "адресIP:порт:модуль" ;-).


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Пятница, 23 Июнь, 2006 12:29 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9147
Откуда: Россия, Орёл
Хорошая идея... Нечто подобное я делал в MtSubscribe, только там модуль подписывает некоторую (ые) свою процедуру на сообщение с определенным именем. Однако писал я это дело давно - и сейчас сделал бы по-другому - подписку не по имени сообщения, а по имени его типа.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Воскресенье, 25 Июнь, 2006 17:33 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
http://www.delphikingdom.ru/asp/talktopic.asp?ID=368
№ 290 24-06-2006 14:10
Илья Ермаков писал(а):
Если говорить о сетевом взаимодействии... Сейчас у меня как раз есть задача организовать параллельные расчеты в сети на взаимодействующих BlackBox-приложениях. Я предполагаю реализовать интерфейс для параллельного взаимодействия следующим образом: среды просто вызывают процедуры друг друга, посылая команды вида Module.Proc и передавая в качестве параметра процедур расширенные записи некоторого базового типа. Билиотека параллельного взаимодействия (БПВ) будет разбирать через метапрограммирование структуру передаваемой записи и выгружать ее поля в линейный поток, передая данные через сокетное соединение вместе с именем типа записи. На "другом конце провода" БПВ по имени типа создает экземпляр того же типа и вызывает требуемую процедуру с передачей параметра. Процедура определяет, какой тип имеет переданный параметр, и либо обрабатывает его, либо игнорирует. Т.е. "тип сообщения" непосредственно ассоциирован с типом объекта в смысле языка программирования. Более того, в стандартном BlackBox Framework есть поддержка перманентных объектов, которая позволяет сериализовать в линейный поток произвольный граф ссылающихся друг на друга перманентых объектов. Поэтому через сеть можно будет легко передать такие объекты, например, графические отображения и т.п. Framework является отличным фундаментом для решения подобных задач, в нем есть все необходимые "кирпичики".

Очень интересно. Я тоже об этом подумывал.

Кстати, на счёт "разбирать через метапрограммирование структуру", на сколько я понимаю, если структура не содержит указателей (а она не должна содержать указателей, коль скоро передаётся на другую машину), то её вроде просто можно побайтово скопировать, т.е. не разбирать через метапрограммирование поля структуры...


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Воскресенье, 25 Июнь, 2006 22:59 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
Сергей Губанов писал(а):
побайтово скопировать

Например, сочиним какую-нибудь эдакую хитрую структурку:
Код:
  TYPE
    Message* = ABSTRACT RECORD END;
   
    T1* = EXTENSIBLE RECORD (Message)
      x*: BYTE
    END;
   
    A1* = ARRAY 2 OF T1;

    T2* = RECORD (Message)
      x*: BYTE;
      t*: T1;
      a*: A1;
      b*: ARRAY 4 OF RECORD x: BYTE END;
    END;

Затем запишем в её поля последовательно 1, 2, 3,...; скопируем её содержимое в массив a и распечатаем элементы массива:
Код:
  PROCEDURE Test0*; (* (!)TestSerialization.Test0 *)
    CONST N = SIZE(T2);
    VAR i: INTEGER;
    r: T2;
    a: ARRAY N OF BYTE;
  BEGIN
    r.x := 1; r.t.x := 2; r.a[0].x := 3; r.a[1].x := 4;
    r.b[0].x := 5; r.b[1].x := 6; r.b[2].x := 7; r.b[3].x := 8;
    FOR i := 0 TO N-1 DO a[i] := 0 END;
    SYSTEM.MOVE(SYSTEM.ADR(r), SYSTEM.ADR(a[0]), N);
    FOR i := 0 TO N-1 DO
      L.String("a["); L.Int(i); L.String("] ="); L.Int(a[i]); L.Ln
    END
  END Test0;

Результат:
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
a[5] = 6
a[6] = 7
a[7] = 8
Значит, вроде как можно, вместо мета-разбора полей, просто побайтово копировать (ну, естественно, это справедливо только если она передаётся на компьютер с тем же порядком big/litle-endian нумерацией битов, но, практически, кроме как на x86 платформе Блэкбокса всё равно пока что-то не видно :D ).


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Понедельник, 26 Июнь, 2006 13:04 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9147
Откуда: Россия, Орёл
Да, можно копировать и побайтно. Но это уже детали реализации.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Пятница, 30 Июнь, 2006 02:17 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9147
Откуда: Россия, Орёл
Сергей, я бы хотел включить Вашу идею в готовящийся Advanced BlackBox Framework (с упоминаем авторства :-) ). Я предлагаю следующий интерфейс:

Код:
DEFINITION AbfBus;
       (* Передать конкретному модулю. Если он не загружен, то будет загружен *)
   PROCEDURE Broadcast (IN module: ARRAY OF CHAR; VAR msg: Message; OUT ok: BOOLEAN);
       (* Передать широковещательно всем загруженным модулям.
Возвращается число модулей, которые имеют HandleBusMsg *)
   PROCEDURE BroadcastAll (VAR msg: Message; OUT count: INTEGER);
       (* Передать всем загруженным модулям указанной подсистемы *)
   PROCEDURE BroadcastSub (IN sub: ARRAY OF CHAR; VAR msg: Message; OUT count: INTEGER);
       (* Передать сообщение всем модулям, подписанным на него *)
   PROCEDURE Send (VAR msg: Message);
       (* Подписать модуль на определенный тип сообщения *)
   PROCEDURE Subscribe (IN mod, msgType: ARRAY OF CHAR);
       (* Отписать модуль *)
   PROCEDURE UnSubscribe (IN mod, msgType: ARRAY OF CHAR);

END AbfBus.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Пятница, 30 Июнь, 2006 11:24 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
Илья Ермаков писал(а):
Сергей, я бы хотел включить Вашу идею в готовящийся Advanced BlackBox Framework (с упоминаем авторства :-) ). Я предлагаю следующий интерфейс:

Круто! Я конечно обоими руками "за".

Только вроде слова Broadcast и Send обозначают ровно наоборот, чем то что тут написано, их надо взаимозаменить. Send - послать по конкретному адресу, а Broadcast - послать всем.

А, кажется, я понял. Вы писали, что у Вас уже используется Subscribe-механизм и, наверное, слово Send Вы уже использовали для него, так что это слово занято. Ничего страшного, ведь ещё есть слово "SendTo" - послать по указанному адресу.

Вот на счёт того что модуль может быть не загружен, это Вы очень правильно заметили. Стоит ли его загружать или не стоит? Кто должен решать? Может быть надо ввести дополнительный флаг forceLoad: BOOLEAN, если forceLoad = FALSE, значит модуль-получатель не надо загружать если он не загружен, иначе - загрузить его?..

Итого:
PROCEDURE Subscribe (IN mod, msgType: ARRAY OF CHAR);
Подписать модуль на определенный тип сообщения.

PROCEDURE UnSubscribe (IN mod, msgType: ARRAY OF CHAR);
Отписать модуль.

PROCEDURE Send (VAR msg: Message);
Передать сообщение всем модулям, подписанным на него.


PROCEDURE SendTo (VAR msg: Message; IN module: ARRAY OF CHAR; forceLoad: BOOLEAN; OUT ok: BOOLEAN);
Передать сообщение msg модулю module. Если этот модуль в данный момент времени не загружен и forceLoad = TRUE, то загрузить его. Результат ok = TRUE говорит о том, что сообщение было доставлено.


PROCEDURE Broadcast (VAR msg: Message; OUT count: INTEGER);
Передать широковещательно всем загруженным модулям всех подсистем. Возвращается число модулей, которым это сообщение было фактически доставлено (имеющим HandleBusMsg).

PROCEDURE BroadcastTo (VAR msg: Message; IN subsystem: ARRAY OF CHAR; OUT count: INTEGER);
Передать широковещательно всем загруженным модулям указанной подсистемы subsystem. Возвращается число модулей, которым это сообщение было фактически доставлено (имеющим HandleBusMsg).


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Пятница, 30 Июнь, 2006 14:56 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9147
Откуда: Россия, Орёл
Полностью согласен.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Пятница, 30 Июнь, 2006 15:56 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
Ещё есть такой "подводный камень" как повторное вхождение внутрь рассылающих процедур. Кто-то послал всем сообщение, процедура рассылки стала его всем рассылать и вдруг кто-то из получивших опять вызвал эту процедуру и т.д. рекурсивно. Т.е. может быть опасным внутри обработчика сообщения посылать новые сообщения, но может быть и не опасным (в зависимости от того будет ли эта рекурсия конечной или бесконечной).

Не смотря на возможную опасность для всей системы, наверное, всё же не надо пресекать повторный вызов, а надеяться на благоразумие программистов - в конце концов от обычной бесконечной рекурсии или зависшего цикла всё равно ни кто не застрахован, а тут ситуация примерно такая же, ну, только межмодульная.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Воскресенье, 09 Июль, 2006 23:50 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9147
Откуда: Россия, Орёл
Вот, в модуле AbfBus выпущенного Advanced BlackBox Framework реализовал идею межмодульной шины. Дополнительно сделал асинхронный вариант с постановкой сообщений в очередь до востребования.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 30 Январь, 2012 18:06 
Модератор
Аватара пользователя

Зарегистрирован: Среда, 16 Ноябрь, 2005 00:53
Сообщения: 4509
Откуда: Россия, Орёл
Оформляю AbfBus без асинхронного варианта как omcBus.

Есть информация, что кто-то был против термина "шина" применительно к данному модулю. Пожалуйста, отпишитесь, пока можно название скорректировать.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 30 Январь, 2012 21:48 
Модератор
Аватара пользователя

Зарегистрирован: Среда, 16 Ноябрь, 2005 00:53
Сообщения: 4509
Откуда: Россия, Орёл
Message заменяется на ANYREC (переписка 26.01.2011):
Евгений Темиргалеев писал(а):
Сергей Губанов писал(а):
Код:
    Message = ABSTRACT RECORD END;

    HandleBusMessage = PROCEDURE (VAR msg: Message);
Сергей, а заведение коренного типа чем-то обосновано? Шина специфических сообщений не определяет, тупо передаёт. Для получения метаинформации, которая используется в реализации, тип переменной роли не играет. Может достаточно просто
HandleBusMessage = PROCEDURE (VAR msg: ANYREC);
?
Сергей Губанов писал(а):
Да, лучше просто ANYREC.
Евгений Темиргалеев писал(а):
ANYREC позволит избавить модуль-обработчик от потребности импортировать модуль-шину, если ему самому ничего слать не надо, а подписывает его на сообщение отдельный конфигурационный модуль

Или я ошибаюсь в чём-то?
Сергей Губанов писал(а):
Да, имортировать необходимости нет.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 31 Январь, 2012 10:12 
Модератор
Аватара пользователя

Зарегистрирован: Среда, 16 Ноябрь, 2005 00:53
Сообщения: 4509
Откуда: Россия, Орёл
Попутно интерфейс сделан более естественным:
1) PROCEDURE Subscribe (IN mod, msgMod, msgType: ARRAY OF CHAR; forceLoad: BOOLEAN);
PROCEDURE UnSubscribe (IN mod, msgMod, msgType: ARRAY OF CHAR);
заменено на:
PROCEDURE Subscribe (IN mod, type: ARRAY OF CHAR; forceLoad: BOOLEAN);
PROCEDURE Unsubscribe (IN mod, type: ARRAY OF CHAR);

2) PROCEDURE BroadcastTo (IN sub: ARRAY OF CHAR; VAR msg: ANYREC; OUT res: INTEGER);
Снято ограничение sub # "".

Исправлено несколько недочётов (журнал --- в тексте модуля).


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 31 Январь, 2012 10:39 
Модератор
Аватара пользователя

Зарегистрирован: Среда, 16 Ноябрь, 2005 00:53
Сообщения: 4509
Откуда: Россия, Орёл
Выложено: http://oberoncore.ru/bbcc/subs/omc/bus


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 31 Январь, 2012 11:59 
Модератор
Аватара пользователя

Зарегистрирован: Среда, 16 Ноябрь, 2005 00:53
Сообщения: 4509
Откуда: Россия, Орёл
"Пока не остыло", решил ещё упростить: отпилена (вместе с зависимостью от Kernel и SYSTEM) подписка на сообщения: Subscribe, Unsubscribe, Send (можно сделать отдельным модулем)

Некоторый опыт практического применения показал, что она не совсем востребована.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 15 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
cron
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2019, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB