Однако, как только рабочий поток завершается, сходство потоков QObject больше не должно быть допустимым.
Рабочий поток НЕ завершается после вызова вашей функции. Весь смысл использования QtConcurrent::run
состоит в выполнении большого количества небольших задач в глобальном пуле потоков (или некоторых из них QThreadPool
), в то время как повторное использование потоков , чтобы избежать накладных расходов создания и уничтожения потоков для каждой из этих небольших задач. В дополнение к распределению вычислений по всем доступным ядрам.
Вы можете попробовать посмотреть на исходный код Qt, чтобы увидеть , как QtConcurrent::run
реализован . Вы увидите, что в итоге он вызывает RunFunctionTaskBase::start
, который по существу вызывает QThreadPool::start
с QRunnable
, который вызывает функцию, которая была первоначально передана в QtConcurrent::run
.
Теперь я хочу добраться до того, чтобы QThreadPool::start
был реализован , добавив QRunnable
в очередь, а затем попытаться разбудить один из потоков из пула потоков. (которые ожидают для добавления нового QRunnable
в очередь). Здесь следует отметить, что потоки из пула потоков не выполняют цикл обработки событий (они не предназначены для таких действий), они просто для выполнения QRunnable
s в очереди и ничего более (они реализованы). таким образом, по причинам производительности, очевидно).
Это означает, что в момент создания QObject
в функции, выполняемой в QtConcurrent::run
, вы просто создаете QObject
, который живет в потоке без цикла обработки событий, из документов , ограничения включают в себя:
Если никакой цикл обработки событий не выполняется, события не будут доставлены объекту. Например, если вы создаете объект QTimer
в потоке, но никогда не вызываете exec()
, QTimer
никогда не будет излучать свой сигнал timeout()
. Звонок deleteLater()
тоже не сработает. (Эти ограничения распространяются и на основной поток.)
TL; DR: QtConcurrent::run
запускает функции в потоках из глобального QThreadPool
(или предоставленного). Эти потоки не запускают цикл обработки событий, они просто ждут выполнения QRunnable
s. Таким образом, QObject
, живущий в потоке из этих потоков, не получает никаких событий.
В документации Они поставили использование QThread
(возможно, с циклом событий и рабочим объектом) и использование QtConcurrent::run
в качестве две отдельные многопоточные технологии. Они не предназначены для смешивания. Итак, нет рабочих объектов в пулах потоков , это просто вызывает проблемы.
Вопрос: автоматически ли Qt перемещает объекты QObject в родительский поток, или мы несем ответственность за их перемещение в допустимый поток до завершения рабочего потока?
Я думаю, что, посмотрев на вещи таким образом, ответ очевиден: Qt автоматически NOT перемещает QObject
s в любой поток. Документация предупреждает об использовании QObject
в QThread
без цикла обработки событий, и все.
Вы можете свободно перемещать их в любую нить, которая вам нравится. Но имейте в виду, что moveToThread()
может иногда вызывать проблемы. Например, если перемещение вашего рабочего объекта предполагает перемещение QTimer
:
Обратите внимание, что все активные таймеры для объекта будут сброшены. Таймеры сначала останавливаются в текущем потоке и перезапускаются (с тем же интервалом) в targetThread. В результате, постоянное перемещение объекта между потоками может отложить события таймера на неопределенное время.
Вывод: Я думаю, вам следует рассмотреть возможность использования собственного QThread
, который запускает свой цикл обработки событий, и создавать там своих рабочих QObject
вместо использования QtConcurrent
. Этот способ намного лучше, чем перемещение QObject
с, и может избежать многих ошибок, которые могут возникнуть при использовании вашего текущего подхода. Взгляните на таблицу сравнения многопоточных технологий в Qt и выберите технологию, которая лучше всего подходит для вашего случая использования. Используйте QtConcurrent
только если вы хотите просто выполнить функцию одного вызова и получить ее возвращаемое значение. Если вы хотите постоянное взаимодействие с потоком, вы должны переключиться на использование своего QThread
с работником QObject
s.