Заявление Яна неточно.Использование moveToThread - это один из способов достижения правильного поведения, но это не единственный метод.
Альтернативой является переопределение метода run и создание ваших объектов, которые должны принадлежать этому потоку.Далее вы вызываете exec ().QThread может иметь сигналы, но убедитесь, что все соединения поставлены в очередь.Также все вызовы в объект Thread должны осуществляться через слоты, которые также подключены через соединение с очередями.В качестве альтернативы вызовы функций (которые будут выполняться в потоке выполнения вызывающих) могут инициировать сигналы для объектов, принадлежащих потоку (созданных в методе run), опять же соединения должны быть поставлены в очередь.
Одна вещь дляобратите внимание, что конструктор и деструктор работают в главном потоке выполнения.Строительство и очистка должны быть выполнены в бегах.Вот пример того, как должен выглядеть ваш метод run:
void MythreadDerrivedClass::run()
{
constructObjectsOnThread();
exec();
destructObjectsOnThread();
m_waitForStopped.wakeAll();
}
Здесь constructObjectsOnThread будет содержать код, который, как вы считаете, принадлежит конструктору.Объекты будут освобождены в destructObjectsOnThread.Фактический конструктор класса вызовет метод exit (), в результате чего exec () завершится.Обычно вы будете использовать условие ожидания, чтобы сидеть в деструкторе до тех пор, пока цикл не вернется.
MythreadDerivedClass::~MythreadDerivedClass()
{
QMutexLocker locker(&m_stopMutex);
exit();
m_waitForStopped.wait(locker.mutex(), 1000);
}
Итак, конструктор и деструктор снова работают в родительском потоке.Объекты, принадлежащие потоку, должны быть созданы в методе run () и уничтожены перед выходом из run.Деструктор класса должен только сообщить потоку о выходе и использовать QWaitCondition, чтобы дождаться, пока поток фактически завершит выполнение.Обратите внимание, что когда все сделано таким образом, у производного класса QThread в заголовке есть макрос Q_OBJECT, и он содержит сигналы и слоты.
Другой вариант, если вы открыты для использования библиотеки KDE, - это поток KDE.Weaver .Это более полная реализация многозадачности, основанная на задачах, аналогичная QtConcurrentRun в том, что она использует пул потоков.Это должно быть знакомо любому, кто имеет опыт работы с Qt.
Тем не менее, если вы открыты для метода c ++ 11 и делаете то же самое, я бы посмотрел на std::async
,Во-первых, вы больше не будете зависеть от Qt, но API также проясняет, что происходит.С классом MythreadDerivedClass, унаследованным от QThread, у читателя создается впечатление, что MythreadDerivedClass является потоком (так как он имеет отношение наследования) и что все его функции выполняются в потоке.Однако в потоке работает только метод run()
.std :: async проще в использовании и имеет меньше ошибок.Весь наш код в конечном итоге поддерживается кем-то другим, и подобные вещи имеют значение в долгосрочной перспективе.
C ++ 11 / w QT Пример:
class MyThreadManager {
Q_OBJECT
public:
void sndProgress(int percent)
void startThread();
void stopThread();
void cancel() { m_cancelled = true; }
private:
void workToDo();
std::atomic<bool> m_cancelled;
future<void> m_threadFuture;
};
MyThreadedManger::startThread() {
m_cancelled = false;
std::async(std::launch::async, std::bind(&MyThreadedManger::workToDo, this));
}
MyThreadedManger::stopThread() {
m_cancelled = true;
m_threadfuture.wait_for(std::chrono::seconds(3))); // Wait for 3s
}
MyThreadedManger::workToDo() {
while(!m_cancelled) {
... // doWork
QMetaInvoke::invokeMethod(this, SIGNAL(sndProgress(int)),
Qt::QueuedConnection, percentDone); // send progress
}
}
По сути, то, что у меня здесь есть, не сильно отличается от того, как ваш код будет выглядеть с QThread, однако этоболее ясно, что в потоке работает только workToDo()
и что MyThreadManager управляет только потоком, а не самим потоком.Я также использую MetaInvoke для отправки очередного сигнала для отправки наших обновлений прогресса с учетом требований к отчету о ходе выполнения.Использование MetaInvoke более явное и всегда делает правильно (не имеет значения, как вы подключаете сигналы от ваших потоковых менеджеров к слотам других классов).Вы можете видеть, что цикл в моем потоке проверяет атомарную переменную, чтобы увидеть, когда процесс отменяется, так что обрабатывает требование отмены.