Qt有两种多线程的方法,其中一种是继承QThread的run函数,另外一种是把一个继承于QObject的类用moveToThread函数转移到一个QThread对象里。 Qt4.8之前都是使用继承QThread的run这种方法,但是Qt4.8之后,Qt官方建议使用第二种方法。 1)用原始的QThread的started信号触发自定义的slot启动线程,而不是派生QThread的类重载run函数启动线程。 将一个类派生自QObject,然后实现所有的signal/slot,然后通过调用movetothread函数来使他们执行在新的线程里面,而不是每次都要重新派生QThread,并且派生QThread的另外一个不好的地方是只有run函数内部的代码才会执行在新线程里面,相比起来,派生QObject并使用movetothread函数更具有灵活性,可以让槽函数执行在新的线程里面。2)自定义对象moveToThread进线程后,事件循环可以完全在此线程中运行。而它的内存管理应该还属于主线程 如下例子中(MyObject* myObj)被moveToThread进线程(QThread thread)。假如对象(MyObject myObj)有父亲,它不能移动这种关系。在另一个线程(而不是创建它的那个线程)中delete QObject对象是不安全的。除非你可以保证在同一时刻对象不在处理事件。可以用QObject::deleteLater(),它会投递一个DeferredDelete事件,这会被对象线程的事件循环最终选取到。3) exec的重要性 主线程开始它的事件循环需要调用QCoreApplication::exec(), 子线程需要用QThread::exec(),功能基本是一样的,当然qt内部肯定是不同的实现。假如没有事件循环运行,事件不会分发给对象。举例来说,假如你在一个线程中创建了一个QTimer对象,但从没有调用过exec(),那么QTimer就不会发射它的timeout()信号,对deleteLater()也不会工作。(这同样适用于主线程)。4) 子线程接收事件 a) 如下例子中,子线程并不存在exec()函数。原因是exec()函数在QThread的run()中调用了。 我们这里并没有做一个QThread派生类,在run中调用exec()。因为我不推荐怎么干。原因很简单,并不需要这么干。进一步说明是:qt提供的QThread已经完全满足线程创建的需要。为什么还要自己再画蛇添足呢。 b) 本例子真正使用的是QCoreApplication::postEvent,和重载QObject类的customEvent的方法。消息一样会在(MyObject* myObj)所在的线程处理。5)关于QCoreApplication::postEvent和QCoreApplication::sendEvent postEvent : 可以给别的线程发送事件。事件会在目的对象所属的线程中运行。这是一个异步接口。 sendEvent : 仅用于同一个线程之间发送事件。目的对象必须与当前线程一样。这是一个同步接口。假如发送给属于另一个线程的对象,会报错:ASSERT failure in QCoreApplication::sendEvent: “Cannot send events to objects owned by a different thread. Current thread a51f48. Receiver ‘’ (of type ‘MyObject’) was created in thread a3bf18”, file kernel\qcoreapplication.cpp, line 53
#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QObject>
#include <QTimer>
#include "myobject.h"
int main ( int argc, char * argv[ ] )
{
QCoreApplication a ( argc, argv) ;
qDebug ( ) << "main:" << ( qlonglong) QThread:: currentThreadId ( ) ;
MyObject* myObj = new MyObject;
QThread * thread = new QThread ( ) ;
QTimer * timer = new QTimer ( ) ;
myObj- > moveToThread ( thread) ;
thread- > start ( ) ;
QObject:: connect ( thread, SIGNAL ( started ( ) ) , myObj, SLOT ( Started ( ) ) , Qt:: QueuedConnection) ;
QObject:: connect ( timer, SIGNAL ( timeout ( ) ) , myObj, SLOT ( Timeout ( ) ) , Qt:: QueuedConnection) ;
timer- > start ( 1000 ) ;
QCoreApplication:: postEvent ( myObj, new QEvent ( CustomEvent_Login) ) ;
qDebug ( ) << QString ( "[%1]send the event: %2!" )
. arg ( ( qlonglong) QThread:: currentThreadId ( ) )
. arg ( CustomEvent_Login) ;
return a. exec ( ) ;
}
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
#include <QEvent>
const QEvent:: Type CustomEvent_Login = ( QEvent:: Type) 5001 ;
class MyObject : public QObject
{
Q_OBJECT
public :
MyObject ( ) ;
protected slots:
void Started ( ) ;
void Timeout ( ) ;
private :
virtual void customEvent ( QEvent * e) ;
} ;
#endif
#include "myobject.h"
#include <QDebug>
#include <QThread>
MyObject:: MyObject ( )
{
}
void MyObject:: Started ( )
{
qDebug ( ) << "Started:" << ( qlonglong) QThread:: currentThreadId ( ) ;
}
void MyObject:: Timeout ( )
{
qDebug ( ) << "Timeout:" << ( qlonglong) QThread:: currentThreadId ( ) ;
}
void MyObject:: customEvent ( QEvent * e)
{
if ( e- > type ( ) == CustomEvent_Login)
{
qDebug ( ) << QString ( "[%1]catch the event: %2!" )
. arg ( ( qlonglong) QThread:: currentThreadId ( ) )
. arg ( e- > type ( ) ) ;
}
}