Qt的一个普遍应用,是用于进行交互式软件开发,往往是需要多任务后台运行,以免阻塞UI界面,这就需要用到多线程,便捷的多线程实现,可以采用C++标准库 std::thread 或 boost:Thread 以及QThread。由于我们本身是使用Qt平台开发,使用QThread是兼容性也是最好,也方便移植,故Qt平台下推荐使用Qt实现多线程方法。
QThread 一般有两种实现方式,一种是继承自QThread,并重载run函数,这种方式的缺陷是,所有的操作必须在run()中进行,并且不被官方建议如此使用;另外一种是继承自QObject,然后moveToThread(),这样QObject的所有方法就会在次线程中运行,此种方式为官方所推荐。此外,如果需要多线程实现QTimer/QTcpSocket等,使用moveToThread方式是最为科学合理的。
下面是一个示例程序,定义一个MyWork类,一个调用类MyTest,通过MyTest类调用MyWork类方法,并且在次线程中运行。
头文件
#include <QObject>
#include <QThread>
class MyWorker : public QObject
{
Q_OBJECT
public:
MyWorker();
~MyWorker();
public slots:
void runWork_1();
void runWork_2();
void runWork_3();
};
class MyTest : public QObject
{
Q_OBJECT
public:
MyTest();
~MyTest();
MyWorker* work;
QThread qt;
void init();
void test();
signals:
void sigWork_1();
void sigWork_2();
void sigWork_3();
};
源文件.cpp
MyWorker::MyWorker()
{
printf("MyWorker: current thread id: %p\n", QThread::currentThreadId());
}
MyWorker::~MyWorker()
{
printf("~MyWorker: current thread id: %p\n", QThread::currentThreadId());
}
void MyWorker::runWork_1()
{
printf("1. current thread id: %p\n", QThread::currentThreadId());
}
void MyWorker::runWork_2()
{
printf("2. current thread id: %p\n", QThread::currentThreadId());
}
void MyWorker::runWork_3()
{
printf("3. current thread id: %p\n", QThread::currentThreadId());
}
MyTest::MyTest()
{
printf("MyTest: current thread id: %p\n", QThread::currentThreadId());
init();
}
MyTest::~MyTest()
{
printf("~MyTest: current thread id: %p\n", QThread::currentThreadId());
}
void MyTest::init()
{
work = new MyWorker;
work->moveToThread(&qt);
connect(this, &MyTest::sigWork_1, work, &MyWorker::runWork_1);
connect(this, &MyTest::sigWork_2, work, &MyWorker::runWork_2);
connect(this, &MyTest::sigWork_3, work, &MyWorker::runWork_3, Qt::DirectConnection);
connect(&qt, &QThread::finished, work, &QObject::deleteLater);
qt.start();
}
void MyTest::test()
{
printf("MyTest: current thread id: %p\n", QThread::currentThreadId());
sigWork_1();
QThread::sleep(1);
sigWork_2();
QThread::sleep(1);
sigWork_3();
QThread::sleep(1);
qt.quit();
qt.wait();
printf("finished!\n");
}
在main.cpp中测试
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// MainWin w;
// w.show();
MyTest mt;
mt.test();
return a.exec();
}
下图为测试结果:
可以看到:
1) MyWorker在主线程中创建
2) runWork_1() 与 runWork_2() 方法均在次线程中执行,并且 MyWorker 在次线程中被析构
3) runWork_3() 在主线程中执行,这是因为 使用了 Qt::DirectConnection,槽函数将立即在当前线程中执行,本例中在主线程中运行。因此,如果对QTimer、QTcpSocket等使用多线程,尽量不要使用 Qt::DirectConnection 连接方式。
综上,使用 moveToThread 后,当前对象QObject被移动到QThread中,所有方法可通过发送signal来调用,并会在QThread中执行,完美实现异步执行。