Небольшая заметка. Часто забываю некоторые нюансы…
О том, что вызов унаследованного от QThread метода run считается некорректным, думаю, писать не стоит — это уже давно разъяснено.
Отмечу здесь некоторые нюансы работы с тредами в Qt, которые мне были нужны и которые приходилось собирать по кускам из сети:
- Отображение прогресса работы треда в QProgressBar
- Принудительное завершение треда
- Возврат из треда результата типа какого-нибудь «крафтового» класса
Итак, как известно, помещение задачи в отдельный тред и её запуск в общем виде выглядит так (например, в функции по нажатию кнопки на главном окне):
//создаем worker - объект от QObject, инкапсулирующий нужный алгоритм,
ThreadWorker *worker = new ThreadWorker();
//создаем объект отдельного потока QThread
thread = new QThread();
//помещаем worker в созданный поток, используя функцию QObject::moveToThread()
worker->moveToThread(thread);
//присоединяем сигналы к слотам
//...об этом позже    
//запускаем поток!
thread->start();Для выполнения задачи в отдельном треде нужно завернуть её в функцию — скажем, process() — отдельного worker-класса, унаследованного от QObject с подключением мета-объектного компилятора MOC путём указания макроса Q_OBJECT:
class ThreadWorker : public QObject
{
    Q_OBJECT
public slots:
    void process();Как видно, главная функция сразу обозначена как слот, который будет вызван по сигналу. Этим сигналом к запуску функции ThreadWorker::process() будет запуск треда QThread::start(). Таким образом, после создания объекта треда и помещения в него экземпляра worker’а, подключаем сигнал к слоту:
connect(thread, SIGNAL(started()), worker, SLOT(process()));Мы хотим получить не только результат работы функции ThreadWorker::process(), но и отображать прогресс её выполнения. А также результат мы хотим получить не в виде стандартного типа, а некоего определённого нами класса ThreadResultType. Таким образом, наш worker должен генерировать сигналы:
class ThreadWorker : public QObject
{
    Q_OBJECT
public slots:
    void process();
signals:
    void finished();
    void result(ThreadResultType result);
    void progress(int value);Сигнал finished() будет привязан к слоту треда deleteLater() для автоматического удаления его объекта. Сигнал progress(int value) привяжем к слоту setValue(int) имеющегося QProgressBar’а, а сигнал result(ThreadResultType result) мы привяжем к созданной нами функции главного окна MainWindow::getThreadResult(ThreadResultType result);
Для того, чтобы можно было передавать свои типы данных через механизм слотов, их нужно зарегистрировать в функции main():
qRegisterMetaType<ThreadResultType>("ThreadResultType");При этом класс, используемый для передачи данных посредством слотов, должен обладать следующими свойствами: иметь конструктор по умолчанию, иметь конструктор копирования и деструктор:
class ThreadResultType
{
private:
    int value;
    QString message;
public:
    ThreadResultType();
    ThreadResultType(const ThreadResultType ©From);
    ThreadResultType(int val, const QString &msg);
    int getValue() const;
    QString getMessage() const;
    void setValue(int value);
    void setMessage(const QString &message);
};Итак, полный набор соединений сигнал-слот, который мы располагаем после создания объекта треда и перед его запуском:
//worker испускает сигнал finished в слот завершения потока
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
//сигнал запуска потока посылаем в функцию worker'а, выполняющую нужную нам работу
connect(thread, SIGNAL(started()), worker, SLOT(process()));
//сигнал worker'а о состоянии прогресса посылаем в слот изменения ProgressBar'а
connect(worker, SIGNAL(progress(int)), ui->progressBar, SLOT(setValue(int)) );
//сигнал worker'а с результатом созданного типа посылаем в слот приема результата
connect(worker, SIGNAL(result(ThreadResultType)), this, SLOT(getThreadResult(ThreadResultType)));
//worker и thread сами удаляют друг друга по завершению работы по сигналу finished()
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));Прелесть параллельно выполняемого кода ещё и в том, что его можно легко прервать без всяких флагов и прочих приседаний в основном процессе. Для этого нужно вызвать метод QThread.requestInterruption(), например, по нажатию кнопки на основной форме в главном потоке:
thread->requestInterruption();Тогда нужно в цикле работы worker’а ThreadWorker::process() отлавливать запрос на остановку треда QThread::currentThread()->isInterruptionRequested():
bool runThread = true;
int loop = 0;
while( (loop < maxLoop) && runThread )
{
    counter++;
    loop++;
    QThread::usleep(100000);
    emit progress(counter);
    runThread = !QThread::currentThread()->isInterruptionRequested();
}После завершения рабочего цикла отправляем результат путем генерации сигналов результата и завершения:
ThreadResultType resultData;
resultData.setValue(counter);
resultData.setMessage(QString("Счетчик равен %1.").arg(counter));
emit result(resultData);
emit finished();





