Обработка сообщений и всё такое
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 18.08.18 20:55
Оценка: +1 :)
Здравствуйте!

Вроде была уже тут такая тема, но я не смог найти, и к чему там пришли, тоже подзабыл

Так что побаяню

Почему сюда — потому что интересуют не абстрактные архитектуры, а плюсовые решения.

Я как-то отстал от жизни, привык один патерн использовать, меня в принципе устраивает, но может, научная мысль уже далеко ушла вперед?

Вот есть некая очередь сообщений/событий. Из неё они извлекаются и как-то обрабатываются.
Мне известны буквально только пара механизмов для реализации такого поведения. Например:

1) Qt. Там из очереди сообщений они извлекаются, где-то в каком-то ассоциативном массиве ищется объект, который подписался на событие, и его слот, и этот слот вызывается, всякие кастинги доп. данных сообщений производятся на основе метаинформации, полученной при помощи метакомпилера. Как-то так вроде, да?
Пользоваться в принципе удобно, но напрягает необходимость препроцессора, и неэффективность данного метода (и не надо мне рассказывать, что на современных системах это копейки )

2) В разных книжках читал, но никогда не использовал — в очередь кладутся уже объекты, которые знают сами, что надо делать (с методом virtual doJob() etc). Никогда не понимал этого. Либо я саму идею не понял правильно, либо что-то еще, но место, где генерируется событие, обычно же ничего не знает о том, как событие должно обрабатывается. Никогда не пробовал применить такой способ.

3) Виндовая очередь оконных сообщений и её обработка. Тут есть вариации: чистый WinAPI со своими message crackers из windowsx.h, WTL со схожим механизмом, MFC. С MFC плотно дела не имел, там вроде немного по другому — уже есть некая "карта" обработки сообщений, которая дергает виртуальные методы, которые переопределяются в пользовательском коде. Из плюсов — отсутствие какого-либо оверхеда вообще. Да и использовать вполне удобно, когда все кракеры уже написаны до нас.

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

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

Дискасс, коллеги
Маньяк Робокряк колесит по городу
Re: Обработка сообщений и всё такое
От: Zhendos  
Дата: 18.08.18 23:12
Оценка: +1
Здравствуйте, Marty, Вы писали:


M>1) Qt. Там из очереди сообщений они извлекаются, где-то в каком-то ассоциативном массиве ищется объект, который подписался на событие, и его слот, и этот слот вызывается, всякие кастинги доп. данных сообщений производятся на основе метаинформации, полученной при помощи метакомпилера. Как-то так вроде, да?

M>Пользоваться в принципе удобно, но напрягает необходимость препроцессора, и неэффективность данного метода (и не надо мне рассказывать, что на современных системах это копейки )

ИМХО конечно, но все это совершенно неверно.
Механизм сигналов и слотов и работа Qt с сообщениями платформы это разные вещи.
Если коротко, то Qt получает события от платформы, некоторые обрабатывает только сама,
большинство превращает в наследников класса QEvent. Любой класс наследующий
от QObject или его детей, может переопределить виртуальный метод "bool QObject::event(QEvent *)"
и проверить QEvent::type и сделать "cast" в правильного наследника QEvent.
После этого он может сделать в принципе что угодно, может сделать "emit signal",
может послать другой QEvent другому объекту, ну или вообще вызывать метод другого объекта
напрямую. Можно также встроиться в систему с помощью "Qt event filter" и перехватывать
события предназначенные другому объекту.
Re[2]: Обработка сообщений и всё такое
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 18.08.18 23:36
Оценка:
Здравствуйте, Zhendos, Вы писали:

M>>1) Qt. Там из очереди сообщений они извлекаются, где-то в каком-то ассоциативном массиве ищется объект, который подписался на событие, и его слот, и этот слот вызывается, всякие кастинги доп. данных сообщений производятся на основе метаинформации, полученной при помощи метакомпилера. Как-то так вроде, да?

M>>Пользоваться в принципе удобно, но напрягает необходимость препроцессора, и неэффективность данного метода (и не надо мне рассказывать, что на современных системах это копейки )

Z>ИМХО конечно, но все это совершенно неверно.

Z>Механизм сигналов и слотов и работа Qt с сообщениями платформы это разные вещи.

Это разные вещи, да. Но я их и не смешивал. Qt всю работу с событиями от платформы преобразует в работу со своими сигналами-слотами. И я хочу обсудить именно это.


Z>Если коротко, то Qt получает события от платформы, некоторые обрабатывает только сама,

Z>большинство превращает в наследников класса QEvent. Любой класс наследующий
Z>от QObject или его детей, может переопределить виртуальный метод "bool QObject::event(QEvent *)"

Qt переваривает сообщения платформы и генерирует свои события, и дальше все идет только в рамках Qt. Я привел как пример именно Qt-шный способ обработки сообщений, вне зависимости, как они были изначально сгенерированы — будь то Win32, или XWindows или еще что-то


Z>и проверить QEvent::type и сделать "cast" в правильного наследника QEvent.

Z>После этого он может сделать в принципе что угодно, может сделать "emit signal",
Z>может послать другой QEvent другому объекту, ну или вообще вызывать метод другого объекта
Z>напрямую. Можно также встроиться в систему с помощью "Qt event filter" и перехватывать
Z>события предназначенные другому объекту.

Да, Qt оставляет возможность обрабатывать системно-зависимые события. И?
Маньяк Робокряк колесит по городу
Re[3]: Обработка сообщений и всё такое
От: Zhendos  
Дата: 19.08.18 00:17
Оценка:
Здравствуйте, Marty, Вы писали:

M>Здравствуйте, Zhendos, Вы писали:


Z>>и проверить QEvent::type и сделать "cast" в правильного наследника QEvent.

Z>>После этого он может сделать в принципе что угодно, может сделать "emit signal",
Z>>может послать другой QEvent другому объекту, ну или вообще вызывать метод другого объекта
Z>>напрямую. Можно также встроиться в систему с помощью "Qt event filter" и перехватывать
Z>>события предназначенные другому объекту.

M>Да, Qt оставляет возможность обрабатывать системно-зависимые события. И?


Словосочетание "системно-зависимые" здесь лишнее.

Если я напишу что-нибудь типа

bool event(QEvent *e) override
{
if (e->type() == QEvent::MouseButtonPress)
}


или

void mousePressEvent(QMouseEvent *event) override


то этот код будет работать и на mac os, и на linux/x11, и на windows,
и даже на android устройстве без мышки.
Это системно независимый код. И именно так предполагается обрабатывать события.

Механизм сигналов/слотов использует event loop/event queue только в случаях
когда объект делающий "emit signal" и объект, который подключился к этому сигналу
в принадлежат разным потокам и использован QueuedConnection тип соединения.
Re[4]: Обработка сообщений и всё такое
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 19.08.18 00:35
Оценка: +1
Здравствуйте, Zhendos, Вы писали:

M>>Да, Qt оставляет возможность обрабатывать системно-зависимые события. И?


Z>Словосочетание "системно-зависимые" здесь лишнее.


Не лишнее.

Z>Если я напишу что-нибудь типа


Z>
Z>bool event(QEvent *e) override
Z>{
Z>if (e->type() == QEvent::MouseButtonPress)
Z>}
Z>


Z>или


Z>
Z>void mousePressEvent(QMouseEvent *event) override
Z>


Это не WM_KEYPRESS или WM_MOUSEMOVE. Это Qtшные события.


Z>то этот код будет работать и на mac os, и на linux/x11, и на windows,

Z>и даже на android устройстве без мышки.
Z>Это системно независимый код. И именно так предполагается обрабатывать события.

Ок.


Z>Механизм сигналов/слотов использует event loop/event queue только в случаях

Z>когда объект делающий "emit signal" и объект, который подключился к этому сигналу
Z>в принадлежат разным потокам и использован QueuedConnection тип соединения.

Приложение без потоков, кроме основного. event-loop'а нет?

В многопоточном приложении еще проще, да?

ЗЫ Чего вы все прикопались к моему вольному описанию системы Qt-шных событий? Я привел его только как один из известных мне вариантов организации взаимодействия изолированных друг от друга частей софтины, когда, например, клавиатура просто генерирует события нажатия клавиш, а в разном прикладном коде эти нажатия клавиш требуется обрабатывать по-разному.
Маньяк Робокряк колесит по городу
Re[5]: Обработка сообщений и всё такое
От: Zhendos  
Дата: 19.08.18 01:13
Оценка: +1
Здравствуйте, Marty, Вы писали:

M>Здравствуйте, Zhendos, Вы писали:


M>>>Да, Qt оставляет возможность обрабатывать системно-зависимые события. И?

Z>>Словосочетание "системно-зависимые" здесь лишнее.
M>Не лишнее.
M>Это не WM_KEYPRESS или WM_MOUSEMOVE. Это Qtшные события.

Вот именно. Qtшные события (QEvent и его дети) это системно независимые события.
В Qt конечно есть способ перехватывать и обрабатывать и WM_KEYPRESS/WM_MOUSEMOVE,
но для этого предназначен другой механизм, и он конечно как раз является
"системно-зависимым", то есть разный для разных ОС.



Z>>Механизм сигналов/слотов использует event loop/event queue только в случаях

Z>>когда объект делающий "emit signal" и объект, который подключился к этому сигналу
Z>>в принадлежат разным потокам и использован QueuedConnection тип соединения.

M>Приложение без потоков, кроме основного. event-loop'а нет?


Есть event loop, и может быть несколько, например при использовании модальных
диалогов, но механизм signal/slot в этом случае его вообще не использует.
Там просто вызов функций напрямую.

M>В многопоточном приложении еще проще, да?


Там сложнее как раз все.

M>ЗЫ Чего вы все прикопались к моему вольному описанию системы Qt-шных событий? Я привел его только как один из известных мне вариантов организации взаимодействия изолированных друг от друга частей софтины, когда, например, клавиатура просто генерирует события нажатия клавиш, а в разном прикладном коде эти нажатия клавиш требуется обрабатывать по-разному.


Потому что описание неверно совсем.
С одной стороны платформо-независимый механизм QEvent и QEventLoop и
платформо-зависимый зависимые механизмы никак не связаны с signal/slot.
С другой стороны в коде ниже,
при вызове
foo.emitSignal();

никакого поиска в ассоциативном массиве не будет,
для каждого сигнала есть его индекс для данного класса,
сначала по индексу мы получим список подключенных к данному сигналу "слушателей",
потому для каждого элемента списка просто вызовем аналог `std::function`,
если все объекты живут в том же потоке (или использован DirectionConnection флаг),
то emitSignal аналогично проходу по `std::list<std::function<>>` и вызову каждой
функции. То есть отличие от прямого вызова функции это только вложенность,
вместо прямого вызова лямбды будет вызов emitSignal, он вызовет QMetaObject::activate,
и потом уже лямбда (может еще пару промежуточных стадий до этого).

class Foo : public QObject {
  Q_OBJECT
signals:
  void sig();

public:
  void emitSignal() { emit sig(); }
};

 
  Foo foo;
  QObject::connect(&foo, &Foo::sig, qApp, [] { qDebug("you call me"); });
  foo.emitSignal();
Re[6]: Обработка сообщений и всё такое
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 19.08.18 01:47
Оценка:
Здравствуйте, Zhendos, Вы писали:


Z>>>Механизм сигналов/слотов использует event loop/event queue только в случаях

Z>>>когда объект делающий "emit signal" и объект, который подключился к этому сигналу
Z>>>в принадлежат разным потокам и использован QueuedConnection тип соединения.

Ну, я в общем не претендовал на доскональное знание кьютешных механизмов. Я спрашивал немного не об этом
Маньяк Робокряк колесит по городу
Re: Обработка сообщений и всё такое
От: LaptevVV Россия  
Дата: 19.08.18 03:14
Оценка: +1
M>2) В разных книжках читал, но никогда не использовал — в очередь кладутся уже объекты, которые знают сами, что надо делать (с методом virtual doJob() etc). Никогда не понимал этого. Либо я саму идею не понял правильно, либо что-то еще, но место, где генерируется событие, обычно же ничего не знает о том, как событие должно обрабатывается. Никогда не пробовал применить такой способ.
Патерн Наблюдатель?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Обработка сообщений и всё такое
От: so5team https://stiffstream.com
Дата: 19.08.18 06:41
Оценка: 30 (1)
Здравствуйте, Marty, Вы писали:

M>Почему сюда — потому что интересуют не абстрактные архитектуры, а плюсовые решения.


Если интересуют плюсовые решения, то:
SObjectizer: что это, для чего это и почему это выглядит именно так?
Давайте заглянем SObjectizer-у под капот
Re[5]: Обработка сообщений и всё такое
От: AlexGin Беларусь  
Дата: 19.08.18 08:59
Оценка:
Здравствуйте, Marty, Вы писали:

M>Да, Qt оставляет возможность обрабатывать системно-зависимые события. И?


Z>>Словосочетание "системно-зависимые" здесь лишнее.


M>Не лишнее.


Да, но только в том случае, если используем какие-либо "системно-зависимые" механизмы:
http://doc.qt.io/qt-5/qcoreapplication.html#installNativeEventFilter и наследование от: QAbstractNativeEventFilter

Иногда применяем и такую "нетрадиционную" методику. Вот подробнее:
http://doc.qt.io/qt-5/qabstractnativeeventfilter.html
http://www.qtcentre.org/threads/56438-help-with-QAbstractNativeEventFilter
http://stackoverflow.com/questions/26652783/qtnativeevent-calls
http://stackoverflow.com/questions/37071142/get-raw-mouse-movement-in-qt
Отредактировано 19.08.2018 9:01 AlexGin . Предыдущая версия .
Re[7]: Обработка сообщений и всё такое
От: Zhendos  
Дата: 19.08.18 09:23
Оценка:
Здравствуйте, Marty, Вы писали:

M>Здравствуйте, Zhendos, Вы писали:



Z>>>>Механизм сигналов/слотов использует event loop/event queue только в случаях

Z>>>>когда объект делающий "emit signal" и объект, который подключился к этому сигналу
Z>>>>в принадлежат разным потокам и использован QueuedConnection тип соединения.

M>Ну, я в общем не претендовал на доскональное знание кьютешных механизмов. Я спрашивал немного не об этом


Разве?
В изначальном вопросе были перечислены три разные альтернативы Qt(1), шаблон наблюдатель(2)
и очередь сообщений (3). И был вопрос:

M>Вот хочу узнать, как подобное можно красиво именно на плюсах реализовать


В нашем обсуждении, я надеюсь, вы уже увидели, что в Qt(1) реализовано и (2) и (3)
и еще один вариант. И даже разобрались, я надеюсь, как это можно красиво именно на плюсах реализовать.
Re: Обработка сообщений и всё такое
От: std.denis Россия  
Дата: 19.08.18 21:27
Оценка:
M>Я как-то отстал от жизни, привык один патерн использовать, меня в принципе устраивает, но может, научная мысль уже далеко ушла вперед?

reactive extensions смотрел?
Re: Обработка сообщений и всё такое
От: c-smile Канада http://terrainformatica.com
Дата: 20.08.18 02:19
Оценка:
Здравствуйте, Marty, Вы писали:

Что-то типа этого:

enum events {
  X = 42,
  Y = 43,
}

struct subscription {
  uint    event_id;
  object* obj;
  std::function<void()> callback;
};

std::list<subscription> g_subscriptions;

void subscribe_to_x_event(object* p) {
  subscription sub = { X, p, [=]() { p->on_x_event(); } };
  g_subscriptions.push_back(sub);
}

void dispatch_event(uint ev_id) {
  for(subscription sub : g_subscriptions) {
    if( sub.event_id == ev_id)
      callback();
  }
}


Только следить чтобы в деструкторе class object он отписывался от всех событий ( unsubscribe(object*p) — оставлен как упражнение для читателя ).
Отредактировано 20.08.2018 2:22 c-smile . Предыдущая версия . Еще …
Отредактировано 20.08.2018 2:22 c-smile . Предыдущая версия .
Re[2]: Обработка сообщений и всё такое
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 20.08.18 05:14
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Что-то типа этого:


А если у каждого события свои собственные параметры есть?
Маньяк Робокряк колесит по городу
Re: Обработка сообщений и всё такое
От: Igore Россия  
Дата: 20.08.18 06:13
Оценка:
Здравствуйте, Marty, Вы писали:

M>Здравствуйте!

M>Вроде была уже тут такая тема, но я не смог найти, и к чему там пришли, тоже подзабыл
M>Так что побаяню

M>Почему сюда — потому что интересуют не абстрактные архитектуры, а плюсовые решения.

Можешь еще boost::signals2 посмотреть, тот же Qt emit в однопоточном режиме, или вообще в сторону RabbitMQ посмотреть, тебе события внутрипрограммные нужны? Опиши задачу, опиши какие бибилиотеки используешь, может в них уже есть свои механизмы, так то можно и через boost::asio или libevent события обрабатывать.
Re[8]: Обработка сообщений и всё такое
От: B0FEE664  
Дата: 20.08.18 08:28
Оценка:
Здравствуйте, Zhendos, Вы писали:

Z>Разве?

Z>В изначальном вопросе были перечислены три разные альтернативы Qt(1), шаблон наблюдатель(2)
Z>и очередь сообщений (3). И был вопрос:

M>>Вот хочу узнать, как подобное можно красиво именно на плюсах реализовать


Z>В нашем обсуждении, я надеюсь, вы уже увидели, что в Qt(1) реализовано и (2) и (3)

Z>и еще один вариант. И даже разобрались, я надеюсь, как это можно красиво именно на плюсах реализовать.

В Qt это совсем не красиво. Мало того, что макросы, так ещё и внешний кодогенератор. Так что это даже не на плюсах.
Чтобы сделать красиво пересылку сообщений в C++ нужна либо рефлексия, либо шаблонные виртуальные функции.
Есть ещё красивый вариант с двойной диспетчеризацией, но на практике он не удобен.
И каждый день — без права на ошибку...
Re[9]: Обработка сообщений и всё такое
От: AlexGin Беларусь  
Дата: 20.08.18 08:39
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>В Qt это совсем не красиво. Мало того, что макросы...


Уже достоточно давно, в Qt5 добавили новый синтаксис — безо всяких макросов:
https://wiki.qt.io/New_Signal_Slot_Syntax

BFE>...так ещё и внешний кодогенератор.

Чем плохо?
Внешний кодогенератор — в общем-то неплохая штука. Один из вариантов автоматизации разработок ПО.

BFE>Так что это даже не на плюсах.

Надстройка над C++ — так сказать корректнее.

P.S. Конечно же, в .NET инфраструктуре обработка сообщений и реализация паттерна Observer (наблюдатель) — выглядит более изящно.
Так ведь и .NET появился лет на двадцать позже, нежели C++
Re[10]: Обработка сообщений и всё такое
От: B0FEE664  
Дата: 20.08.18 09:34
Оценка:
Здравствуйте, AlexGin, Вы писали:

BFE>>В Qt это совсем не красиво. Мало того, что макросы...

AG>Уже достоточно давно, в Qt5 добавили новый синтаксис — безо всяких макросов:
AG>https://wiki.qt.io/New_Signal_Slot_Syntax

Q_OBJECT остался.

BFE>>...так ещё и внешний кодогенератор.

AG>Чем плохо?
AG>Внешний кодогенератор — в общем-то неплохая штука. Один из вариантов автоматизации разработок ПО.
Внешний инструмент всегда требует существенных затрат на его настройку. Например, компиляция Qt кода из-под Visual Studio требует существенных временных затрат на настройку проекта.

BFE>>Так что это даже не на плюсах.

AG>Надстройка над C++ — так сказать корректнее.
Надстройка над C++ — это уже не С++.
И каждый день — без права на ошибку...
Re[11]: Обработка сообщений и всё такое
От: Igore Россия  
Дата: 20.08.18 11:14
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>>>...так ещё и внешний кодогенератор.

AG>>Чем плохо?
AG>>Внешний кодогенератор — в общем-то неплохая штука. Один из вариантов автоматизации разработок ПО.
BFE>Внешний инструмент всегда требует существенных затрат на его настройку. Например, компиляция Qt кода из-под Visual Studio требует существенных временных затрат на настройку проекта.
Ого, а можно подробности? У меня всегда былы скачай Add In, Next, Next, Install, пользуйся.
Re[11]: Обработка сообщений и всё такое
От: AlexGin Беларусь  
Дата: 20.08.18 11:54
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Внешний инструмент всегда требует существенных затрат на его настройку. Например, компиляция Qt кода из-под Visual Studio требует существенных временных затрат на настройку проекта.


Пользуюсь Qt v5.11.0 как совместно с MSVC-2017, так и с MSVC-2015.
Проект открывается сходу.
Настройка — однократная, для всего Qt VS Tools (Qt VS Addin), а не для каждого отдельного проекта.

Есть два варианта открыть проект:
1) Меню "Qt VS Tools"->"Open Qt Project File (.pro)..." — при этом создаётся проект .vcproj (в стандартах MSVS);
2) Если проект и солюшен были ранее созданы (открытием по 1-му варианту), то просто открываем из Меню "File"->"Recent...".

ЧЯДНТ?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.