Как избежать Qt app.exec(), блокирующего основной поток
Я новичок в Qt, но мне нужно решить сложную проблему.
Я создал ОЧЕНЬ простой графический интерфейс, который мне нужно добавить в существующее приложение C++. Проблема в том, что я пишу только один модуль, который подключается к более крупной архитектуре, которая ограничивает мой доступ к основному потоку.
Мой код должен находиться внутри следующих четырех функций: функция Init(), которая выполняется в основном потоке. и функции WorkerStart(), WorkerStep() и WorkerStop(), которые выполняются в рабочем потоке.
Я кодировал свои объекты QApplication и GUI в функции Init(). Но, конечно, вызов app.exec() в конце этой функции блокирует весь остальной код. Не работает
Все, что я читаю, говорит о том, что объекты Qt gui могут выполняться только в основном потоке.
Итак, мой вопрос, как я могу настроить свой графический интерфейс в функции init() (основной поток) и разрешить его запуск только с помощью рабочего потока с этого момента?
Я нашел это: QApplication в неосновной теме
и эти решения дали мне другое поведение. В правильном направлении, но не стабильно или не полностью функционально. Но я не понимаю, почему это вообще решения, если qt gui могут работать только в основном потоке, а эти решения помещают их в другие потоки. Так что отправка смешанных сообщений о том, что может и не может работать в других потоках, и это становится очень запутанным.
Кажется, что добавление графического интерфейса в существующую программу на C++ без блокировки в функции exec () должно быть довольно распространенной ситуацией, поэтому я чувствую, что упускаю что-то очевидное. Может кто-нибудь помочь с тем, как я могу решить это?
Большое спасибо заранее. Фил
1 ответ
В большинстве случаев, "основной поток" == "поток GUI", поэтому люди используют эти термины взаимозаменяемо - даже официальная документация делает это. Я согласен, что это сбивает с толку, потому что они не должны быть одинаковыми.^ Фактическое правило таково:
Доступ к классам GUI возможен только из потока, который создает
QApplication
/QGuiApplication
С таким плагином, как у вас, вот что вам нужно сделать:
- Создать новый
std::thread
(НЕQThread
) - Запустить
init
функция в этой теме. Пусть это создастQApplication
/QGuiApplication
и запустить цикл событий - Убедитесь, что все ваши объекты GUI доступны только из этого потока.
Вуаля, теперь у вас есть поток GUI, который не является вашим основным потоком.
^Примечание: это другая история в Mac OS X. Из-за ограничений в структуре Какао основным потоком ДОЛЖЕН быть поток GUI. Шаги, которые я описал выше, будут работать в Windows/Linux, но не в Mac. Для Mac вам нужно вставить свой код в основной поток - см. Комментарии Кубы Обера ниже.
Хорошее решение можно найти в: git@github.com:midjji/ удобный_multithreaded_qt_gui.git
тогда это просто например
run_in_gui_thread(new RunEventImpl([](){
QMainWindow* window=new QMainWindow();
window->show();
}));
вызывается из любого потока, в любое время, при этом заботясь о настройке для вас в bg.
Обратите внимание, что это также касается создания QApplication и его выполнения в потоке. Но также работает, если вы уже это где-то уже сделали.