2012-07-01 2 views
0

Я в настоящее время (перо) проектирование системы, которая состоит из нескольких частей:Последовательный алгоритм с асинхронными событиями

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

Главный вопрос: если есть рекомендации по организации такого кода?

Решение, которое я придумал и не очень люблю, - это запустить 4 потока.

  • графический поток, который обменивается данными с помощью сигналов Qt с 3 другими нитями
  • Рама источником резьбы, который выдает сигнал на каждом наличии кадра.
  • Кадровый органайзер, который хранит кадры по сигналу и использует QWaitCondition для уведомления о потоке процессора кадра.
  • Поток процессорного процессора, который вызывает getNextFrame() из организатора кадра.

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

ответ

1

Нет необходимости использовать QWaitCondition. Нити должны быть голыми (не производными) QThreads. Поместите весь свой код в пределах QObjects, которые перемещаются в эти потоки. Организатор кадра просто посылает сигналы на процессор кадра. Сигналы передаются через границы потоков, отправляя события в цикл событий потока. Эти циклы событий внутренне используют примитивы синхронизации (мьютексы) для серализации доступа, поэтому нет необходимости изобретать колесо там. Реализация QThread по умолчанию run() просто закручивает цикл событий, поэтому вам не нужно ничего делать, кроме создания экземпляра потока и его запуска.

Ваш код должен работать, возможно, с пониженной производительностью, со всеми объектами QObject, созданными в потоке графического интерфейса пользователя. Перенос их в отдельные потоки будет выполняться, когда ваш бенчмаркинг показывает, какие объекты связаны с ЦП. Существует грустное, но необходимое исключение из этого правила: если ваш код камеры может использовать только блокирующие API, предоставляемые драйвером камеры (API-интерфейсы, которые ждут чего-то вместо асинхронного сообщения об этом), тогда у вас нет выбора, кроме как пожертвовать нить для этого , За исключением таких выделенных потоков блокировки-обхода, ваше приложение должно использовать примерно столько потоков, сколько есть доступных ядер (QThread::idealThreadCount()). Вы должны создать экземпляр такого количества потоков и распределить QObjects среди этих потоков случайным образом или циклически. Опять же - только перемещайте объекты QObject, которые связаны с CPU. Объекты, связанные с IO, которые используют неблокирующий APis (сеть!), Не нуждаются в этом лечении. Драйвельные драйверы устройств (например, от http://www.ftdichip.com/) предоставляют асинхронные уведомления о событиях, которые могут быть преобразованы в сигналы по QWinEventNotifier. Это частный API в Qt 4.x, но работает отлично, несмотря на это.

Очень жаль, что множество распространенных API-интерфейсов блокируются. Драйверы баз данных являются типичным примером.Я закончил перенос драйвера клиента mysql, чтобы использовать, например, QTcpSocket, чтобы база данных не блокировала поток, который ее использует.

+0

Я понимаю ваш ответ и содержит много полезной информации для меня. Однако мой главный вопрос заключался в том, как преобразовать управляемую событиями парадигму (события frameReady()) в последовательную обработку ('while (getNextFrame()) processFrame()'). Я столкнулся с решениями с запуском локального цикла событий ('QEventLoop') и подключением нужного сигнала (' frameReady() ') к слоту' quit() '. Однако это выглядит уродливо для меня, и, как я понял, имеет свои недостатки - может помешать нормальному ходу обработки сигнальных слотов. Извините, если я не был достаточно ясен в своей первоначальной формулировке. – fAX

+0

Чтобы быть более конкретным, я хотел бы иметь возможность выразить алгоритм: 'frame = wait4goodFrame();/* вызывает getNextFrame() внутренне */ doSmth (frame); doSmthElse (getNextFrame()); ' вместо обработки его в слоте ' void processFrame (frame) {if (weAreWaiting4goodFrame && isGoodFrame (frame)) doSomth (frame); прочее если (weAreInStage2) doSmthElse (рамка); else if ...} ' Это менее читаемо и имеет огромный шаблонный код. – fAX

+0

Преобразование событий в последовательную обработку - это именно то, что вы * не * должны делать. Читабельность/шаблонная таблица минимальны, если ваш код не является тривиальным. 'If ​​(weAreWaiting4goodFrame ...' означает, что вы хотите конечный автомат, которые лучше всего выражаются непосредственно в повторной реализации 'void customEvent (QEvent *)'. Для элементарного FSM просто отправьте указатель метода и получите один метод для каждого состояния. Это способ правильно спроектировать его. Механизм состояний Mangling в последовательной обработке работает только с самого начала. Когда вы начинаете обрабатывать восстановление ошибок и т. д., код становится спагетти. –