суббота, 25 августа 2012 г.

Рекомендуемый путь использования QThread в Qt 4.4 и выше

Qt предоставляет класс QThread для создания многопоточных приложений. К сожалению, существует некоторая путаница относительно того, как нужно использовать QThread. Данный пост рассказывает о основе, заложенной в класс QThread, а также описывает то, как Вы должны использовать Q-потоки в Ваших приложениях.

Не создавайте подклассов QThread!
Большая часть путаницы происходит из-за того, что QThread используется как абстракатный класс. Такуим образом, единсветнный путь использования Qthread - это создание его подкласса и переопределение метода run(). И это действительно было так, до версии Qt 4.4, начиная с которой метод QThread::run() получил реализацию по умолчанию, следовательно необходимость в создание потомков класса QThread отпала. Главной причиной этому послужил тот факт, что создание потомков класса QThread может препятствовать использованию слотов подклассом.

Единственная причина, по которой, Вам по-прежнему может понадобиться создавать потомки класса QThread - это создание своего собственного цикла приложения(application run-loop).

Используйте moveToThread() и "рабочий" класс, подкласс QObject.
Далее описано, как Вы должны реализовать многопоточную операцию используя класс QThread.
Для начала, создайте "рабочий" класс, который унаследован от класса QObject.
Этот класс должен определять следующие сигналы и слоты:
  • Слот, в котором происходит вся основная работа.
  • Сигнал, который информирует вызывающий код о завершении работы.
  • * Опционально, сигнал, который информирует вызывающий код в случае возникновения ошибок.
"Рабочий" класс может выглядеть так:
class Worker : public QObject {
 Q_OBJECT
 public:
  Worker();
  virtual ~Worker();
 public slots:
     void process();

 signals:
     void finished();
     void error(QString err);
};
Далее, используйте QThread в связке с Вашим "рабочим" классом, для выполнения многопоточной работы:
// Создание потока
QThread* thread = new QThread;
Worker* worker = new Worker();

// Передаем права владения "рабочим" классом, классу QThread.
worker->moveToThread(thread);

// Связываем сигнал об ошибки со слотом обработки ошибок(не показан).
connect(worker, SIGNAL(error(QString)), this, SLOT(errorHandler(QString)));

// Соединяем сигнал started потока, со слотом process "рабочего" класса, т.е. начинается выполнение нужной работы.
connect(thread, SIGNAL(started()), worker, SLOT(process()));

// По завершению выходим из потока, и удаляем рабочий класс
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));

// Удаляем поток, после выполнения операции
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

thread->start();

Заметка является переводом с форума поддержки разработчиков Blackberry.