Динамическое излучение одного объекта в наборе - PullRequest
1 голос
/ 09 января 2012

У меня есть ситуация, когда у меня есть один объект-эмиттер и набор приемников. Приемники относятся к одному классу и фактически представляют собой набор устройств одного типа. Я использую фреймворк Qt.

  • Сам эмиттер сначала получает сигнал с запросом информации от одного из устройств.

  • В соответствующем слоте Эмитент должен проверить, какой из приемников «готов», а затем отправить свой собственный сигнал для запроса данных на одно из устройств (в зависимости от того, что готово первым).

Эмиттер получает сигналы очень быстро, порядка миллисекунд. Есть три способа безопасного запроса данных только от одного из устройств (устройства живут в своих собственных потоках, поэтому мне нужен механизм с защитой потоков). Количество устройств не является статичным и может меняться. Общее количество устройств довольно мало (определенно под 5-6).

1) Подключайтесь ко всем устройствам, когда они добавляются или удаляются. Создайте один запрос и попросите объекты устройств самим отфильтровать, является ли запрос для них определенным тегом устройства. Этот метод хорош тем, что слот запроса, в котором происходит проверка, будет выполняться в контексте выделенного потока, но расточителен по мере увеличения количества устройств.

2) Подключайтесь и отключайтесь от объекта внутри Эмиттера на лету, когда необходимо отправить запрос.

3) Используйте QMetaObject :: invokeMethod (), когда необходимо отправить запрос.

Производительность важна. Кто-нибудь знает, какой метод является «лучшим» или вообще есть лучший?

Привет

Цена

Примечание: для уточнения: Emitter получает сигнал из приложения, чтобы получить информацию, запрашивая устройство. Безумный ASCII art go:

(приложение) <----> (излучатель) <------> (приемники) <- | -> физические устройства

Ответы [ 2 ]

0 голосов
/ 08 июня 2016

Мне забавно, что это многопоточная среда.

Если вы ограничены системой сигналов / слотов Qt между тем, ответьте на ваши конкретные вопросы:

1) это определенно не тот путь. При выделении из Emitter общее число событий, равное количеству Receivers, будет поставлено в очередь для циклов событий потока (ов) устройств, тогда такое же количество вызовов слотов произойдет, как только поток (ы) ) достичь тех событий. Даже если большинство из них потеряли всего if(id!=m_id) return; на своей первой строке, в ядре Qt происходит значительное количество вещей. Поместите точку останова в один из ваших слотов, которая вызывается сигналом Qt::QueuedConnection, и проверьте это, глядя на фактическую трассировку стека. Обычно от глубины xyEventLoop::processEvents(...) по крайней мере 4 колла, поэтому «просто возвращение» определенно не «бесплатно» с точки зрения времени.

2) Не уверен, какова на самом деле внутренняя реализация Qt, но из того, что я знаю, подключение и отключение, скорее всего, включают вставку и удаление отправителя и получателя в некоторые списки, к которым, скорее всего, доступ осуществляется с помощью блокировки QMutex. - может также быть «дорогим» по времени, и быстрое подключение и отключение определенно не лучшая практика.

3) Пожалуй, самое дешевое по времени решение, которое вы можете найти, все еще использующее систему синг-слотов Qt.

опционально) Взгляните на QSignalMapper. Он предназначен именно для того, что вы планировали сделать в варианте 1).

Существуют более оптимальные решения для связи между вашими Emitter и Receivers, но в качестве лучшей практики я бы сначала выбрал вариант, который наиболее прост в использовании и быстр в реализации, но при этом имеет шанс быть быстрым достаточно времени выполнения (это вариант 3). ). Затем, когда это будет сделано, посмотрите, соответствует ли оно вашим требованиям к производительности. Если это не так и только тогда, рассмотрите возможность использования совместно используемой памяти с мьютексами в поставщике данных - архитектура потребителя данных (поток Emitter быстро публикует данные запроса в циклическом списке, в то время как поток (потоки) Receiver читает их всякий раз, когда время, затем отправляйте результаты обратно аналогичным образом, в то время как поток Emitter постоянно опрашивает готовые результаты.)

0 голосов
/ 09 января 2012

Исходя из предоставленной вами информации, я все равно рекомендую реализацию Reactor.Если вы не используете ACE, вы можете реализовать свой собственный.Базовая архитектура выглядит следующим образом:

  1. используйте select для пробуждения при получении сигнала или данных из приложения.
  2. Если в списке отправки есть готовый сокет, тоВы просто выбираете один и отправляете ему данные
  3. Когда данные отправляются, Receiver удаляет себя из набора доступных сокетов / обработчиков
  4. Когда данные обрабатываются, Reciever повторнорегистрируется в списке доступных получателей.

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

...