Russian Qt Forum
Ноябрь 22, 2024, 10:14 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Паттерн Active оbject  (Прочитано 4879 раз)
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« : Август 09, 2019, 09:10 »

Существует такой паттерн, как Active object, который предназначен для организации асинхронного вызова методов целевого класса путем формирования поверх него обертки.
В недрах самой обертки присутствует планировщик задач, поток исполнения и т.п.

Если интерфейс класса имеет, например, вид

Код
C++ (Qt)
class Passive // Implementation
{
public:
   Result doSomething ();
}
 

то можно сформировать обертку вида

Код
C++ (Qt)
class Active // Proxy
{
public:
   Future< Result > doSomething ();
};
 

В этом кратком обзоре все понятно. Метод вызывает законченное действие, ждем результат завершения на Future.

Но далее возник вопрос - Что если метод провоцирует цепочку действий (сценарий) или запускает какой-то событийный цикл (прием данных, например)?
При этом важным является не только факт завершения вызываемого метода (как у Future) , но и порядок происходящих событий (стадии сценария, пакеты принимаемых данных и т.п.).

Реализация для этого случая может выглядеть так

Код
C++ (Qt)
class Active
{
public:
   Future< Result > doSomething ();
   //...
   Events takeEvents ();    
};
 

В этом случае необходимо периодически забирать события у объекта. Есть сомнения в таком решении, так как, если не забрать события, то они могут копиться бесконечно.

Другой вариант - отдавать события через callback, но это требует внешних средств синхронизации со стороны пользователя Активным объектом, и в этом случае пользователь имеет возможность затормозить или вообще заблокировать очередь задач Активного объекта.

Может есть другие варианты? Может требуется другой паттерн? Что посоветуете?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Август 09, 2019, 21:00 »

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

Насколько мне известно, упомянутый паттерн весьма общий - ну контроллер асмнхронки - вот собсно и все.

Но далее возник вопрос - Что если метод провоцирует цепочку действий (сценарий) или запускает какой-то событийный цикл (прием данных, например)?
При этом важным является не только факт завершения вызываемого метода (как у Future) , но и порядок происходящих событий (стадии сценария, пакеты принимаемых данных и т.п.).
В этом случае необходимо периодически забирать события у объекта.
...
Другой вариант - отдавать события через callback,
Может точнее "фильтровать события" (контроллером)? Ну почему нет, это вполне возможно. Но плохо это или хорошо - "зависит от задачи" (любимое выражение всех сачков  Улыбающийся)
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #2 : Август 09, 2019, 23:16 »

Давайте конкретизируем на примере известной задачи).
Рассмотрим подключение tcp клиента к серверу.
Можно обернуть реализацию сокета Активным объектом ("контроллером асинхронки")

Код
C++ (Qt)
class TcpClient
{
...
   Future< bool > connect ();
...
};
 

Кроме факта подключения/не подключения, получаемого через Future, имеются события изменения состояния TcpClient
По аналогии с Qt, пусть это будет:
Код:
UnconnectedState
HostLookupState
ConnectingState
ConnectedState

Каким лучше способом получить данные события от TcpClient?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Август 10, 2019, 01:42 »

Давайте конкретизируем на примере известной задачи).
Рассмотрим подключение tcp клиента к серверу.
Мне эта задача незнакома, с сетью практически не работаю

Каким лучше способом получить данные события от TcpClient?
Наверное как TcpClient (контроллер) получит события изменения статуса. Ну напр связать любимыми слот/сигнал вениками Улыбающийся
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #4 : Август 10, 2019, 10:45 »

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

Другой вариант - отдавать события через callback, но это требует внешних средств синхронизации со стороны пользователя Активным объектом, и в этом случае пользователь имеет возможность затормозить или вообще заблокировать очередь задач Активного объекта.
Это традиционное решение для таких случаем.
Да, клиент должен понимать, что callback-функция вызывается из контекста исполнителя операции, и для корректной обработки применять возможность своего окружения. Например, класть сообщение о смене состояния в очередь сообщений для дальнейшей обработки и обрабатывать их в своих контекстах.
Затормозить или заблокировать это право клиента. Ему можно даже дать возможность штатно прервать операцию посередине. Улыбающийся
Это все уже проблемы клиента.
« Последнее редактирование: Август 10, 2019, 15:40 от Old » Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #5 : Август 12, 2019, 07:37 »

Мне эта задача незнакома, с сетью практически не работаю

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

Наверное как TcpClient (контроллер) получит события изменения статуса. Ну напр связать любимыми слот/сигнал вениками Улыбающийся

Это собственно и есть вариация callback).
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #6 : Август 12, 2019, 08:46 »

Это решение не информативно для клиента объекта. Он не может отслеживать момент смены состояния, ему доступно только список того, что уже произошло с объектом.

Согласен), это собственно и смущает.

... Но клиенту чаще важней вовремя получать информацию о смене состояния ...

Клиент объекта и сам объект по сути контекстно независимы. Понятия одновременности, вовремя и т.п. для них относительны.
Здесь, скорее всего, уместен термин, "своевременно", а не "вовремя". Хотя и так понятно о чем речь).

Это традиционное решение для таких случаев ...

С "традиционным решением" не согласен. Бывает по разному. Например, для сети на posix, традиционным является как раз периодический опрос наличия данных ::select, и вычитывания всего, что пришло ::recv.
Или для любого другого межпроцессного взаимодействия, приходится периодически опрашивать какой-нибудь обобщенный ресурс (память, файлы и т.п.).

Но соглашусь, что реализация через callback является предпочтительнее, когда между производителем и потребителем можно организовать прямые взаимосвязи.
Тогда и потребителей может быть много, и каждый из них может сам решить, обрабатывать события списком или по одному и каким образом.
По-началу почему-то показалось, что существует какая-то разница между событиями, порождаемыми Активным объектом, и событиями, порождаемыми каким-то произвольным генератором. Но похоже, что нет).

« Последнее редактирование: Август 12, 2019, 12:33 от ssoft » Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.169 секунд. Запросов: 23.