QThread не запускается
Извините за длину этого поста. Но я застрял на два дня...
Я работаю над приложением Qt 4.6 для Windows, которое связывается с аппаратным устройством через ActiveX.
Когда я посылаю команду, устройство выполняет какие-то действия, а когда оно выполнено (может занять до одной минуты), оно издает сигнал. Мне нужно дождаться этого сигнала, чтобы узнать, все ли прошло хорошо (или нет), и выполнить некоторые действия в последствии.
Команда отправляется на устройство, когда пользователь нажимает кнопку. И, очевидно, я не хочу, чтобы HMI зависал.
Я убежден, что я должен использовать темы. Итак, я определил три темы:
- основной поток, соответствующий HMI
- аппаратный контроллер (который блокируется после отправки команды и ждет сигнала)
- слушатель аппаратного уведомления, который непрерывно получает сигналы от аппаратного обеспечения и разблокирует поток 2
Вот диаграмма классов:
И диаграмма последовательности, чтобы показать, как я вижу вещи:
Пояснения:
Когда пользователь запускает мое приложение, HMI создается. Конструктор HMI вызывает конструктор Worker. Он конструирует аппаратный QAxObject. Затем он создает HardwareListener с указанием ссылки: QAxObject, QMutex и QWaitCondition. Затем конструктор Worker перемещает объект HardwareListener в другой поток и запускает его. Наконец, конструктор HMI запускает поток Worker.
Затем, когда пользователь нажимает кнопку, HMI посылает сигнал работнику. Рабочий отправляет команду оборудованию (эта команда может заблокировать поток на несколько секунд, поэтому мне необходим HardwareListener в другом потоке, чтобы не пропустить сигнал). Затем работник ожидает QWaitCondition (после блокировки QMutex).
После этого аппаратное устройство отправляет сигнал в HardwareListener, который активирует QWaitCondition. Поэтому рабочий поток прекращает ждать и завершает свои действия. Наконец, работник информирует HMI.
Проблема:
Потоки Worker и HardwareListener не создаются / не запускаются. Все сделано в основном потоке, поэтому, очевидно, это не работает. Я не обмениваюсь никакими специальными объектами между потоками (поэтому нет необходимости qRegisterMetaType()
)
Вопрос:
Мой дизайн приемлем? Могут быть и другие способы, но, как мне кажется, это самый простой способ (учитывая сложность).
РЕДАКТИРОВАТЬ:
Я изменил свой код, чтобы удалить QThread
наследование. Я использую moveToThread()
метод вместо.
Теперь темы работают нормально. ОДНАКО у меня есть ошибка ActiveX: QAxBase: Error calling IDispatch member NewProject: Unknown error
,
Кажется, взаимодействие с оборудованием нарушено... Есть идеи?
You cannot move a QAxObject to another thread once it has been created.
РЕШЕНИЕ:
1 ответ
Наследование от QThread не является хорошим дизайном. Если работа, которую вы выполняете, требует больших вычислительных ресурсов, я бы порекомендовал использовать QThreadPool. Я не лучше использовать асинхронный дизайн. Это означает только вызов функции, которая никогда не блокирует, а подключается к сигналам, уведомляющим вас о том, что что-то произошло
Так, например, отправка команды аппаратному обеспечению и выдача сигнала, когда аппаратное обеспечение выполнено. Если аппаратный API не предоставляет асинхронные функции, то вы застряли с использованием потоков. QtConcurrentRun может помочь с этим. Обычно вам не нужно трогать темы самостоятельно; и чертовски намного проще без.