最近开发中遇到PyQt多线程问题,后来在谷歌上看了大量的资料,发现QThread正确使用方式。官方提供的继承QThread实现多线程,是一种错误的做法,具体怎么错,可以查看如下链接,本文不深入探讨。
http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/
具体使用摘自一篇博客如下所述:
The main thing to keep in mind when using a QThread is that it’s not a thread. It’s a wrapper around a thread object. This wrapper provides the signals, slots and methods to easily use the thread object within a Qt project. This should immediately show why the recommended way of using QThreads in the documentation, namely to sub-class it and implement your own run() function, is very wrong. A QThread should be used much like a regular thread instance: prepare an object (QObject) class with all your desired functionality in it. Then create a new QThread instance, push the QObject onto it using moveToThread(QThread*) of the QObject instance and call start() on the QThread instance. That’s all. You set up the proper signal/slot connections to make it quit properly and such, and that’s all.
上文之意就是说:不要把QThread当成一个thread,它仅仅是用来把object包装为thread对象的包装器而已。这个包装器提供了信号,槽等各种易使用的方法。官方文档中提到的继承QThead类,然后重写run方法,是一种错误的方式。正确方式是:创建一个QObject对象,这个对象包含了你想调用的函数,然后创建一个QThread实例,把QObject对象通过moveToThread()方法放到线程里,通过调用QThread的start()方法来启动QObject的方法,从而实现线程操作。
代码如下:
首先创建一个QObject对象,worker对象,真正做事的对象:
class Worker : public QObject { Q_OBJECT public: Worker(); ~Worker(); public slots: void process(); signals: void finished(); void error(QString err); private: // add your variables here };
// --- CONSTRUCTOR --- Worker::Worker() { // you could copy data from constructor arguments to internal variables here. } // --- DECONSTRUCTOR --- Worker::~Worker() { // free resources } // --- PROCESS --- // Start processing data. void Worker::process() { // allocate resources using new here qDebug("Hello World!"); emit finished(); }
上述代码需要注意的是:
By the way, one extremely important thing to note here is that you should NEVER allocate heap objects (using new) in the constructor of the QObject class as this allocation is then performed on the main thread and not on the new QThread instance, meaning that the newly created object is then owned by the main thread and not the QThread instance. This will make your code fail to work. Instead, allocate such resources in the main function slot such as process() in this case as when that is called the object will be on the new thread instance and thus it will own the resource.
不要在构造函数里使用new创建对象,一旦创建,对象将不属于QThread实例,这样会使代码无法正常运行。new对象应该放到process()函数里。
下面是核心的地方,如何使用QThread
QThread* thread = new QThread; Worker* worker = new Worker(); worker->moveToThread(thread); connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString))); 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();
具体更多,请参考:
文章的脚注信息由WordPress的wp-posturl插件自动生成