Ответ 1
Я бы сосредоточился на различиях между этими двумя методами. Существует не общий ответ, который подходит для всех случаев использования, поэтому хорошо понимать, что именно они должны выбрать, что подходит вашему делу.
Использование moveToThread()
moveToThread() используется для управления привязкой к потоку объектов, что в основном означает настройку потока (или, лучше, цикла событий Qt), из которого объект будет излучать сигналы, и его слоты будут выполнены.
Как показано в документации, которую вы связали, ее можно использовать для запуска кода в другом потоке, в основном создавая манекена, записывая код для запуска в общедоступном слоте (в примере слот doWork()), а затем используя moveToThread для переместите его в другой цикл событий.
Затем загорается сигнал, подключенный к этому слоту. Поскольку объект, который испускает сигнал (контроллер в примере), живет в другом потоке, и сигнал подключен к нашему методу doWork с подключением по очереди, метод doWork будет выполнен в рабочем потоке.
Ключевым моментом здесь является то, что вы создаете новый цикл событий, выполняемый рабочим потоком. Следовательно, как только слот doWork запустится, весь цикл событий будет занят до тех пор, пока он не выйдет, а это означает, что входящие сигналы будут поставлены в очередь.
Подкласс QThread()
Другим способом, описанным в документации Qt, является подкласс QThread. В этом случае один переопределяет стандартную реализацию метода QThread :: run(), который создает цикл событий, для запуска чего-то еще.
В этом подходе нет ничего плохого, хотя есть несколько уловов.
Прежде всего, очень легко написать небезопасный код, потому что метод run() является единственным в этом классе, который будет фактически запущен в другом потоке.
Если в качестве примера у вас есть переменная-член, которую вы инициализируете в конструкторе, а затем используете в методе run(), ваш член инициализируется в потоке вызывающего, а затем используется в новом потоке.
Такая же история для любого общедоступного метода, который может быть вызван либо из вызывающего, либо внутри run().
Также слоты будут выполняться из потока вызывающего абонента (если вы не сделаете что-то действительно странное, как moveToThread (this)), что приведет к дополнительной путанице.
Таким образом, это возможно, но вы действительно сами по себе с этим подходом, и вы должны уделять дополнительное внимание.
Другие подходы
Конечно, есть альтернативы для обоих подходов, в зависимости от того, что вам нужно. Если вам просто нужно запустить некоторый код в фоновом режиме во время работы потока GUI, вы можете использовать QtConcurrent :: run().
Однако имейте в виду, что QtConcurrent будет использовать глобальный QThreadPool. Если весь пул занят (это означает, что в пуле нет доступных потоков), ваш код не будет запущен немедленно.
Другой альтернативой, если вы хотя бы на С++ 11, является использование API нижнего уровня, такого как std :: thread.