Как избежать основной блокировки Qt app.exec()
Я новичок в Qt, но мне нужно решить сложную проблему.
Я создал ОЧЕНЬ простой графический интерфейс, который мне нужно добавить в существующее приложение на С++. Проблема в том, что я пишу только один модуль, который подключается к более крупной архитектуре, которая ограничивает мой доступ к основному потоку.
Мой код должен находиться внутри четырех следующих функций:
функция Init(), которая запускается в основном потоке.
и WorkerStart(), WorkerStep() и WorkerStop(), которые выполняются в рабочем потоке.
Я закодировал объекты QApplication и GUI в функции Init(). Но, конечно, вызов app.exec() в конце этой функции блокирует весь остальной код. Не работает.
Все, что я читаю, говорит, что объекты Qt gui могут работать только в основном потоке.
Итак, мой вопрос в том, как настроить мой gui в функции init() (основной поток) и разрешить ему запускать только с помощью рабочего потока с этого момента?
Я нашел это: QApplication In Non-Main Thread
и эти решения дали мне другое поведение. В правильном направлении, но не стабильный или полностью функциональный. Но я не понимаю, почему это решения вообще, если qt gui может работать только в основном потоке, и эти решения помещают их в другие потоки. Таким образом, отправка смешанных сообщений на что может и не может выполняться в других потоках, и это становится очень запутанным.
Кажется, что добавление gui к существующей программе на С++ без блокировки в функции exec() должно быть довольно распространенной ситуацией, поэтому я чувствую, что мне не хватает чего-то очевидного. Может кто-то помочь с тем, как я могу это решить?
Большое спасибо заранее.
Фил
Ответы
Ответ 1
В большинстве случаев "основной поток" == "поток GUI", поэтому люди используют эти термины взаимозаменяемо - даже официальная документация делает это. Я согласен с тем, что это запутывает, потому что они не обязательно должны быть одинаковыми. ^ Фактическое правило таково:
Классы GUI должны быть доступны только из потока, который создает экземпляр QApplication
/QGuiApplication
С плагином, подобным вашему, вот что вам нужно сделать:
- Создайте новый
std::thread
(НЕ a QThread
)
- Запустите функцию
init
в этом потоке. Пусть он создает экземпляр QApplication
/QGuiApplication
и запускает цикл событий
- Убедитесь, что все ваши объекты GUI доступны только из этого потока.
Voila, теперь у вас есть поток GUI, который не является вашим основным потоком.
^ Примечание. Это другая история в Mac OS X. Из-за ограничений в структуре Cocoa основной поток ДОЛЖЕН быть потоком GUI. Шаги, описанные выше, будут работать на Windows/Linux, но не на Mac. Для Mac вам нужно ввести код в основной поток - см. Комментарии Kuba Ober ниже.