Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.82/11: Рейтинг темы: голосов - 11, средняя оценка - 4.82
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
1

Цикл, обрабатывающий события от нескольких источников

25.03.2017, 02:32. Показов 1971. Ответов 15
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте, форумчане!
Помогите, пожалуйста, решить такую проблему, которая меня заинтересовала.

Требуется создать цикл обработки событий или сообщений от двух или более источников. Т. е., допустим, имеется несколько (более одного) источника событий, каждый из них порождённые им события помещает в свою очередь, причём эти очереди разные, общей единой очереди событий, в которую все источники делали бы запись, не существует. События могут считываться из очередей любым возможным способом — могут использоваться для этого системные вызовы операционной системы (допустим, read/write в Unix и Linux), мьютексы и блокировки чтения/записи, какие-то специальные библиотечные функции и т. п. Источники событий могут быть любые — пайпы, FIFO, сокеты, X Server, посылающий клиентской программе события клавиатуры и мыши, и т. п. Главное, чтобы их было несколько, при этом они могут быть и однотипными, и совершенно разной природы.

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

В случае одного источника событий задача тривиальна и не вызывает никаких вопросов. А как быть, если их несколько? Какие существуют решения и подходы?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
25.03.2017, 02:32
Ответы с готовыми решениями:

Построить цикл, обрабатывающий строки матрицы
подскажите , пожалуйста, в чем проблема. есть матрица o, нужно выполнить операцию над каждым ее...

Отчет из нескольких источников данных
Может делал кто. Топик не совсем в эху но тем не менее Имеем разные базы на разных серверах...

Слияние в Word из нескольких источников
Есть наборы математических задач с формулами (MathType или Equation), набранные в Word (одна тема -...

Сбор данных из нескольких источников
Уважаемые форумчане! И великие УМЫ!!! Подскажите макрос, который переносил бы таблицу на один лист...

15
Заблокирован
25.03.2017, 02:57 2
Цитата Сообщение от JohnyWalker Посмотреть сообщение
В случае одного источника событий задача тривиальна и не вызывает никаких вопросов
для нескольких источников задача так же тривиальна, так как есть специально созданные для таких целей вызовы: select, poll, epoll.
1
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
25.03.2017, 08:27  [ТС] 3
nimazzzy, спасибо за ответ. Я не знал о существовании этих системных вызовов, а поэтому у меня родилось такое решение.

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

Интересно, что вы думаете о такой схеме. Мне кажется, она вполне работоспособна, но неоправданно сложна для такой задачи. Городить для каждого источника сообщений свою отдельную нить (thread) для такой элементарной задачи излишество. В конце концов, потоки в Unix появились довольно поздно, а описанная мной задача наверняка существовала гораздо раньше и была решена другими более простыми и изящными средствами.
0
Заблокирован
25.03.2017, 16:53 4
Цитата Сообщение от JohnyWalker Посмотреть сообщение
Для каждого источника создать свой отдельный поток (pthread), а в нём запустить свой маленький простенький цикл обработки событий именно для этого источника.
Тогда не нужны вызовы для проверки дескрипторов. Каждый поток и так будет висеть на чтении.
Цитата Сообщение от JohnyWalker Посмотреть сообщение
главный поток, со своим циклом обработки сообщений, который обрабатывал бы все события ото всех источников.
А почему эту "обработку" тогда каждый поток не может сам сделать?
Цитата Сообщение от JohnyWalker Посмотреть сообщение
Интересно, что вы думаете о такой схеме.
Я думаю, что надо исходить из задачи. А ты начинаешь с решения какой-то абстрактной сущности с какими-то абстрактными обработками. Поэтому я тут никак не думаю, так как у меня нет ТЗ.
1
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
25.03.2017, 21:13  [ТС] 5
Цитата Сообщение от nimazzzy Посмотреть сообщение
Тогда не нужны вызовы для проверки дескрипторов. Каждый поток и так будет висеть на чтении.
Цитата Сообщение от JohnyWalker Посмотреть сообщение
главный поток, со своим циклом обработки сообщений, который обрабатывал бы все события ото всех источников.
А почему эту "обработку" тогда каждый поток не может сам сделать?
Всё правильно — эту обработку мог бы сделать и каждый поток по отдельности. Просто я не знал о существовании вызовов вроде select и poll, а хотел организовать всё-таки обработку событий от разных источников в одном потоке, в одном цикле обработки сообщений. Поэтому мне и пришлось по сути дела имитировать работу этих системных вызовов, создавая для каждого источника свой висящий на нём поток. А мьютекс, который бы эти потоки, висящие на источниках, освобождали и через который они бы управляли головным потоком с главным циклом обработки сообщений, как раз бы играл роль системного вызова select или poll. Вместо блокирующего системного вызова select или poll главный поток блокировался бы в цикле, допустим, на вызове pthread_mutex_lock.

Т. е. я не знал вызовов select и poll, а хотел симитировать подобное поведение известными мне средствами и сделать основную обработку всё-таки в одном потоке.

Цитата Сообщение от nimazzzy Посмотреть сообщение
Я думаю, что надо исходить из задачи. А ты начинаешь с решения какой-то абстрактной сущности с какими-то абстрактными обработками. Поэтому я тут никак не думаю, так как у меня нет ТЗ.
Такая задача у меня есть, пусть и в довольно расплывчатой формулировке. Чуть позже о ней напишу.
0
Заблокирован
25.03.2017, 21:42 6
JohnyWalker, а, я понял! Ты описал решение, которое у тебя родилось до того, как ты узнал про select. Все, вопросов больше не имею
1
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
26.03.2017, 01:05  [ТС] 7
А вот и сама задача.

Имеется мысль написать некоторую интерфейсную иксовую GUI программу, которая бы выводила некоторую информацию, рисовала таблицы, показывала рисунки и графики. При этом программа, с одной стороны бы использовала ввод от пользователя, т. е. события X Server'а от мыши и клавиатуры (она бы управлялась пользователем, как любая GUI-программа), а с другой стороны использовала бы какой-то механизм IPC (например, FIFO) в качестве источника внешних данных от других программ. Допустим, через FIFO ей бы поставлялись данные с датчиков каких-то приборов. К примеру, мы могли бы написать систему управления каким-то устройством и нас бы интересовали его параметры — температура, напряжение, ток, частота вращения двигателя и т. п. (хотя это всего лишь один из многих примеров).

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

1. Пользовательский ввод — события клавиатуры и мыши.

2. Внешние входные данные, поставляемые ей через FIFO (или какой-либо иной механизм IPC).

И тут возникает вопрос, как данные, поступающие от этих двух источников, обрабатывать. В целом, логично их обрабатывать в цикле. Но тут можно поступить двояко.

Для каждого из двух источников — X Server'а и FIFO — можно создать свой цикл обработки событий и запустить каждый цикл в своём потоке. Тогда события от обоих источников будут обрабатываться параллельно и независимо, а при необходимости (когда между ними будут возникать какие-то противоречия) потоки будут синхронизировать друг друга через мьютексы и rw_lock'и.

Можно поступить иначе. Можно использовать единый общий цикл обработки событий, который будет фиксировать появление данных, поступающих как от X Server'а, так и от FIFO, и обрабатывать их. При этом, несмотря на два различных источника данных, цикл обработки данных будет один и работать он будет в одном потоке. Но тут возникает проблема — блокироваться и разблокироваться цикл должен на какой-то функции, регистрирующей наличие или отсутствие данных не в одном, а в двух источниках. При отсутствии данных в обоих источниках функция должна становиться в ожидание, а при наличии данных хотя бы в одном из источников функция должна "открываться". Вот и встаёт вопрос, как в такой системе, использующей с одной стороны X Server, а с другой стороны FIFO, сразу проверить состояние данных в обоих источниках и при появлении их хотя бы в одном источнике разблокироваться.

Работа с иксами может производиться через любую библиотеку — Xlib, GTK+, QT, причём Xlib для меня сейчас наиболее предпочтительный вариант. Как известно, все эти библиотеки для считывания событий оконной системы используют какую-нибудь функцию, например Xlib использует функцию XNextEvent(). Вот и возникает вопрос, как, имея с одной стороны файл FIFO, а с другой стороны функции чтения событий из очереди вроде XNextEvent(), сделать проверку наличия данных и там, и там, и организовать общий "сводный" цикл, обрабатывающий события и из того, и из другого источника.

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

Добавлено через 22 минуты
P.S.
Пишу так гуманитарно и многословно потому что планы и представления, как это всё должно работать, очень расплывчаты пока. Да и похожих вещей не делал раньше, с подобными проблемами сталкиваюсь впервые.

Добавлено через 1 час 28 минут
nimazzzy, какие у тебя мысли есть?
0
Заблокирован
26.03.2017, 23:39 8
Лучший ответ Сообщение было отмечено JohnyWalker как решение

Решение

С xlib не работал, но, учитывая архитектуру иксов (клиент-сервер на сокетах), там можно и в одном потоке сделать с select'ом. Используя ConnectionNumber получить дескриптор сокета и вперед. Но, если обработка данных перед отображением - штука затратная, то я бы разделил на потоки.
1
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
27.03.2017, 03:52  [ТС] 9
nimazzzy, спасибо тебе за ответ. Что интересно, такое же решение этой проблемы предлагают и на англоязычных форумах вроде stackoverflow. Вот ссылки с примерами кода, вдруг кому-нибудь это будет интересно.

http://stackoverflow.com/quest... xnextevent
http://stackoverflow.com/quest... chronously
http://www.linuxquestions.org/... ?p=2431345 — здесь наиболее подробное обсуждение и больше всего примеров исходников, поэтому эту ссылку наверное стоит рекомендовать в первую очередь
http://stackoverflow.com/quest... er-process
http://stackoverflow.com/quest... ent-occurs

Добавлено через 12 минут
nimazzzy, ещё такой вопрос. Мне никогда ранее ни с select(), ни с poll()/epoll() не приходилось работать. Где обо всём этом (ну, прежде всего, о select()) почитать? Книжка "Стивенс, Раго" сойдёт?
0
Заблокирован
27.03.2017, 10:52 10
Не знаю про Стивенса, библия для меня - книга Kerrisk'а. Он пишет офигенно. Правда, не знаю есть ли на русском.
1
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
27.03.2017, 20:00  [ТС] 11
nimazzzy и другие, напоследок такой вопрос. Для общего развития.
А как моя проблема (случай, когда поступающие события надо обрабатывать не только от оконной системы, но и от какого-то другого источника и чтобы чтение событий от оконной системы не блокировало события от второго источника) решается не в xlib, а средствами GTK+ и QT? Тоже нужно получить дескриптор сокета иксов и использовать вызов select()? Или там, может, для решения этой задачи существуют свои специальные средства, специфичные именно для этих библиотек?

Добавлено через 2 часа 5 минут
И всё-таки мой вопрос по QT и GTK+. Он для меня так остро сейчас не стоит, но всё же... Может, есть у кого-нибудь какие-то мысли и соображения?
0
6045 / 2160 / 753
Регистрация: 10.12.2010
Сообщений: 6,005
Записей в блоге: 3
28.03.2017, 08:59 12
JohnyWalker, вам нужен не просто цикл. Вам нужна реализация паттерна event queue.
1
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
28.03.2017, 09:56  [ТС] 13
Цитата Сообщение от HighPredator Посмотреть сообщение
JohnyWalker, вам нужен не просто цикл. Вам нужна реализация паттерна event queue.
HighPredator, уточните, пожалуйста, говоря о паттерне event queue, какую библиотеку вы имеете в виду — Xlib, GTK+ или QT? Или вы имеете в виду все их вместе?

И что значит словосочетание "паттерн event queue"? В переводе с английского это означает очередь событий. Понятно, что работая в цикле с сообщениями от любой оконной системы, в т. ч. и с иксами, какую бы библиотеку я не использовал, я в любом случае работаю с очередью событий и выполняю из неё чтение. Но, может быть, в таких кроссплатформенных библиотеках как QT или GTK+ термином "паттерн event queue" обозначается какая-то особая сущность, какая-то специфическая конструкция этой библиотеки, объявленная в ней? Поясните, что вы имели в виду под этим термином, можно и со ссылками на документацию Xlib, GTK+, QT или какой-либо иной библиотеки, которую вы подразумевали.
0
6045 / 2160 / 753
Регистрация: 10.12.2010
Сообщений: 6,005
Записей в блоге: 3
28.03.2017, 13:44 14
Цитата Сообщение от JohnyWalker Посмотреть сообщение
какую библиотеку вы имеете в виду — Xlib, GTK+ или QT
Ни одну из них ибо не знаком. Допускаю, что в них есть готовые реализации сего.
Цитата Сообщение от JohnyWalker Посмотреть сообщение
что значит словосочетание "паттерн event queue"? В переводе с английского это означает очередь событий
В точку. Только ключевая особенность этого паттерна в том, что он позволяет работать с множеством источников разных архитектурно разных(!) событий. Есть две вырожденные (сферические в вакууме) типичные реализации этого паттерна как краевые случаи. Первый это идеальный игровой движок, в котором осуществляется разруливание событий сети, рендеринга, пользовательского ввода, игрового процесса и прочих. Все они разные архитектурно и независимы друг от друга. В этом основная цель паттерна: осуществлять взаимодействие между системами, поддерживая архитектурную развязанность систем друг с другом как и должно быть (decoupling, loose coupling). Второй вырожденный случай, это когда тип, источник и обработчик возникающих событий один. Яркий пример -- простой цикл обработки сообщений в винапи.

Да, это не простой паттерн, но и у вас задача соответствующая. Что-то еще вам подрассказать?
0
techpriest
634 / 213 / 57
Регистрация: 27.02.2014
Сообщений: 1,180
28.03.2017, 14:00 15
Хочу заметить, что реализация с кучей потоков, каждый из которых обрабатывает свой канал и скидывает свой выхлоп в "очередь событий" гораздо мощнее системного select.
0
Заблокирован
28.03.2017, 14:29 16
Цитата Сообщение от Mirmik Посмотреть сообщение
реализация с кучей потоков, каждый из которых обрабатывает свой канал и скидывает свой выхлоп в "очередь событий" гораздо мощнее системного select
Это неправильное утверждение. "Может быть производительнее в некоторых случаях" - это да.
0
28.03.2017, 14:29
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
28.03.2017, 14:29
Помогаю со студенческими работами здесь

Чтение по http из нескольких источников
Доброго времени суток!!! Есть 25 источников, которые по http предоставляют данные вида: X:00000...

Формирование отчета из нескольких источников
Всем привет. Как через скд или другой вариант формирование отчета вывести в нем 2 таблицы друг под...

Поиск из нескольких источников данных
Добрый день, не могли бы Вы помочь с решением казалось простой задачи.... Имеется 2 таблицы...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru