Мы пытаемся написать переносную разделяемую библиотеку, которая для удобства использует некоторые классы Qt (главным образом QTimer
а также QTcpSocket
); но без графического интерфейса. Соответствующие соединения сигнал / слот, по-видимому, требуют некоторой петли событий Qt, поэтому мы «заправляем» QCoreApplication
как указано в этот ответ. Соответственно, мы устанавливаем рабочий объект, который выполняет тяжелую работу, и перемещаем его в QThread
,
Проблема, с которой мы сейчас сталкиваемся, состоит в том, что очереди между QThread
объект владельца (в основном потоке) и рабочий объект в пределах QThread
похоже, никогда не обрабатывается в системах Linux, по крайней мере, до тех пор, пока программа, реализующая нашу библиотеку, не предоставляет какой-либо свой собственный цикл событий Qt в основном потоке. Это не очень полезно, поскольку данные, передаваемые рабочим в основной поток, должны передаваться дальше с использованием некоторых функций обратного вызова, которые теперь никогда не вызываются.
Мой вопрос таков: есть ли способ заставить цикл событий работать в главном потоке библиотеки, не блокируя его или не запуская основную программу (что, похоже, имеет место при установке QCoreApplication::exec()
или подобное там)? Или нам нужно будет установить другую схему связи между потоками (независимо от Qt), чтобы справиться с этими передачами данных?
Поскольку мы не знаем, будет ли программное обеспечение хоста работать на QApplication
или нет, в идеале я бы также проверил это перед настройкой цикла событий основного потока. Простой if(qApp != nullptr)
достаточно для этого?
П.С .: Несколько вещей, которые я пробовал, но у меня тоже ничего не получалось:
QEventLoop
в std::thread
запускается из основного потока (вероятно, не работает, потому что все еще не в основном потоке)QEventLoop
в классе основного потока и запуска его processEvents()
функционировать периодически, используя QTimer
(вероятно, не работает из-за отсутствия цикла событий для QTimer::timeout
сигнал в основной функции)QCoreApplication
в std::thread
(выдает предупреждение во время выполнения в Windows, что QCoreApplication должен быть запущен в главном потоке)На языке Qt обратный вызов называется Qt::DirectConnection
, Но, конечно, эти обратные вызовы будут выполняться в вашем рабочем потоке. Но это было бы в случае с любой другой библиотекой, которая использует обратные вызовы, поэтому Qt здесь не является проблемой, как и ваш код: основная идея имеет это свойство.
Если хост-приложение не использует цикл обработки событий (любой цикл обработки событий, не обязательно Qt), то вы ничего не можете сделать, кроме опроса — см. Ниже.
Если хост-приложение запускает цикл событий X11, вам нужно убедиться, что ваша копия Qt использует тот же базовый цикл событий, что и хост-приложение. Обычно это цикл событий glib, и тогда он должен работать автоматически. В противном случае вам нужно будет передать пользователю файловый дескриптор примитива синхронизации, используемого циклом событий Qt, и пользователю нужно будет интегрировать его в свой цикл событий. Вы столкнетесь с той же проблемой, используете ли вы Qt или нет: использование собственного метода связи не исправит его, поскольку вам все еще нужен ожидаемый примитив, который будет взаимодействовать с любым циклом событий, который использует пользователь.
Пользователь может, конечно, опросить обратные вызовы, когда захочет: выставить mainPoll()
метод, который направляет QCoreApplication::processEvents()
,
Несмотря на принятие другого ответа (который я считаю более правильным), я все же хотел бы упомянуть обходной путь, который работал на удивление хорошо: нам фактически удалось обойти проблемы цикла / потока событий в большинстве систем, соединив сигналы рабочего потока с лямбда-функциями в конструкторе класса, который устанавливает рабочий.
Теперь я сомневаюсь, что это поведение правильно поточно-ориентированное и имеет относительно длинные лямбда-функции, объявленные в connect
вызовы функций, конечно, не хороший стиль. Но в случае, если кто-то еще столкнется с этой проблемой, это может быть краткосрочное решение или (временный) обходной путь.