Перенос объекта Qt в отдельный поток
Правильный перенос объекта Qt в отдельный поток происходит следующим образом:
1. Создать поток QThread.
2. Выполнить метод moveToThread() для нужного объекта, указав ему созданный на этапе 1 поток.
3. Настроить сигнал-слотовые соединения (connect) для перемещенного объекта. Для того, чтобы вызовы слотов происходили корректно из других потоков, при настройке connect() надо указывать тип соединения Qt::QueuedConnection.
4. Старт потока через метод start(). Данный метод можно вызывать и после шага 2, работать тоже будет без проблем.
5. Если в объекте используются таймеры QTimer, их старт надо навесить либо на слот обработки старта потока, либо делать запуск в уже перенесенном в поток объекте. Таймеры не работают, если они были запущены, а потом объект был перенесен в другой поток.
Выполнение кода
Всегда следует помнить, что при прямом вызове метода объекта, или при вызове слота объекта в обычном режиме (когда происходит непосредственный вызов слота), код метода или слота выполняется в потоке, в котором был произведен вызов! Другими словами: даже если объект был перенесен в отдельный поток, его метод или слот, при обычном вызове, будет выполняться в вызывающем потоке.
Чтобы вызов слота был "отвязан" от вызывающего потока, и слот объекта выполнялся в потоке, в который объект был перемещен, установку сигнал-слотового соединения нужно делать с флагом Qt::QueuedConnection, как это было описано выше. В этом случае запуск слота происходит в потоке объекта, которому принадлежит слот. Для запуска слота, Qt вначале размещает вызов в очередь основного цикла приложения, и сам запуск слота происходит при обработке основного цикла приложения.
Завершение работы потока
Завершать работу потока можно примерно следующим кодом:
myThread->quit();
if( !myThread->wait(2000) )
{
myThread->terminate();
}