Как избежать 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

С таким плагином, как у вас, вот что вам нужно сделать:

  1. Создать новый std::thread (НЕ QThread)
  2. Запустить init функция в этой теме. Пусть это создаст QApplication/QGuiApplication и запустить цикл событий
  3. Убедитесь, что все ваши объекты 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 и его выполнения в потоке. Но также работает, если вы уже это где-то уже сделали.

Другие вопросы по тегам