QThread类提供了独立于平台的处理线程类。
在程序中,一个QThread对象处理一个线程。QThread通过start方法创建一个新线程,新线程调用run方法(所以在程序中看到的是run方法在新线程中运行。是否只有run方法运行在新线程中?)。默认情况下,run方法通过调用exec方法启动事件循环,并在线程内运行Qt 事件循环。当退出run方法将会终止这个新线程。
你可以通过QObject::moveToThread方法将worker对象移动到某个线程中。
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
} ~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
上面的例子中worker对象中的slot代码可以在一个独立的线程中运行。但是,你可以使用任何线程中的任何类对象的信号函数(signal)来链接这个槽函数(slot)。通过使用Qt的队列链接(queued connections)链接不同线程中的信号槽是线程安全的。
另一种在独立线程运行的方法是实现QThread类的run方法。例如:
class WorkerThread : public QThread{
Q_OBJECT
void run() Q_DECL_OVERRIDE {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &s);
};
void MyObject::startWorkInAThread()
{
WorkerThread *workerThread = new WorkerThread(this);
connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
在此例中,独立线程会在run方法返回时退出。除非你调用exec方法,不会有任何事件循环在此线程中运行。
我们需要理解的是:创建的QThread实例只是存在旧线程中,只有run方法运行在新线程中。这就意味着所有的QThread的队列槽函数只会在旧线程中运行。如果开发者想在新的线程中调用槽函数,只能使用第一个例子;新的槽函数不必再继承QThread的子类重写。
当继承QThread类,构造函数是在旧线程中执行而run方法则是在新线程中实现。如果一个成员字段可以被构造函数和run方法方法访问,那么这个字段也会被2个线程访问。程序员应确保在访问时数据时安全可靠地。
注:当在不同的线程内操作对象进行交互时,可以看同步线程(Synchronizing Threads)的执行细节。