1、QTread 不是在 main 中开始,而是在run开始运行。
2、QTread 开始start(),通过调用run()执行线程。
3、start()如果试图开始一个已经运行的线程,这个调用将一直等待,直到这个线程完成,然后再重新开始这个线程。
4、run() 方法是纯虚的函数,为了能够做有用的工作必须在继承类中被重新实现。run()中的执行语句都是在新起的一个线程中执行,默认实现是QThread::exec(),表示开始线程的消息循环,就可以接收信号,并执行相应的槽。
=================================================================================
5、Qt 的线程与事件循环
1、不推荐的实现方式>>>>>>>>1
#defineDUMMY_H
#include<QObject>
#include<qDebug>
#include<QThread>
classDummy:publicQObject
{
Q_OBJECT
public:
explicitDummy(QObject*parent=0);
publicslots:
voidemitsig(){
qDebug()<<"Dummythread:"<<QThread::currentThreadId();
emitsig();
}
signals:
voidsig();
};
#endif//DUMMY_H
===============================================================================
#ifndefTHREAD_H
#defineTHREAD_H
#include<QThread>
#include<qDebug>
//===================================================================================//
//Qt::DirectConnection:When emitted, the signal is immediately delivered to the slot.
//不能跨线程传递消息。
//===================================================================================//
//Qt::QueuedConnection
//When emitted, the signal is queued until the event loop is able to deliver it to the slot.
//将信号包装成QEvent消息,放到消息队列里,QApplication::exec或者线程的QThread::exec()会从消息队列里取消息,然后调用 signal关联的 slot。这种方式既可以在线程内传递消息,也可以跨线程传递消息。 对应的槽函数在接收者所依附的线程中执行。
//===================================================================================//
//Qt::AutoConnection
//If the signal is emitted from the thread in which the receiving object lives, the slot is invoked directly,as with Qt::DirectConnection; otherwise the signal is queued, as with Qt::QueuedConnection.
//这种连接类型根据signal和slot是否在同一个线程里,自动选择Qt::DirectConnection或Qt::QueuedConnection。
//===================================================================================//
//QThread 依附的线程,就是执行构造出此线程的线程,即主线程
//QThread 管理的线程,就是 run 启动的线程,即次线程
//默认连接(AutoConnection)情况下,由于消息的传递是跨线程的,故表现为队列连接(QueuedConnection),同时QThread的对象依附在主线程中,所以它的 slot 函数会在主线程中执行,而不是QTread对象的线程,即次线程中执行。除非信号发射和接收都在次线程中(通过movetoThread 将QTread 对象依附到次线程中)———— Bradley T. Hughes 不支持这种方式。
//===================================================================================//
classThread:publicQThread{
Q_OBJECT
public:
Thread(QObject*parent=0):QThread(parent)
{ //此时自动连接等同于队列连接,即槽函数在接受者所依附线程执行
moveToThread(this);//故改变依附的线程,也就是自己,使其依附的线程为次线程,信号和slot在同一个线程中
}
publicslots:
voidslot_main()//如果没有moveToThread(this),此槽函数在依附线程,即主线程中执行
{
qDebug()<<"fromthreadslot_main:"<<currentThreadId();
}
protected:
voidrun()//在新线程中执行
{
qDebug()<<"threadthread:"<<currentThreadId();
exec();
}
};
#endif//THREAD_H
===============================================================================
#include<QCoreApplication>
#include"dummy.h"
#include"thread.h"
#include<qDebug>
intmain(intargc,char*argv[])
{
QCoreApplicationa(argc,argv);
qDebug()<<"mainthread:"<<QThread::currentThreadId();
Threadthread;
Dummydummy;
QObject::connect(&dummy,SIGNAL(sig()),&thread,SLOT(slot_main()));
thread.start();
dummy.emitsig();//发射sig()信号
returna.exec();
}
================================================================================
Bradley T. Hughes推荐的方式:
1.在Qt4.3(包括)之前,run 是虚函数,必须子类化QThread来实现run函数。
2.从Qt4.4开始,qthreads-no-longer-abstract,run 默认调用 QThread::exec(),则不需要子类化 QThread ,只需要子类化一个QObject 就够了。
3.QThread应该被看做是操作系统线程的接口或控制点,而不应该包含需要在新线程中运行的代码。
4.QObject的子类提供运行的代码中,然后将QObject子类的对象 moveToThread 到新线程QTread子类中。
#ifndefDUMMY_H
#defineDUMMY_H
#include<QThread>
#include<qDebug>
classDummy:publicQThread
{
Q_OBJECT
public:
explicitDummy(QObject*parent=0);
signals:
voidsig();
publicslots:
voidemitsig()
{
emitsig();
}
};
#endif//DUMMY_H
===============================================================================
#ifndefOBJECT_H
#defineOBJECT_H
#include<QObject>
#include<qDebug>
#include<QThread>
classObject:publicQObject
{
Q_OBJECT
public:
explicitObject(QObject*parent=0);
signals:
publicslots:
voidslot()
{
qDebug()<<"fromthreadslot:"<<QThread::currentThreadId();
}
};
#endif//OBJECT_H
==============================================================================
#include"dummy.h"
#include"object.h"
#include<QCoreApplication>
#include<qDebug>
intmain(intargc,char**argv){
QCoreApplicationa(argc,argv);
qDebug()<<"mainthread:"<<QThread::currentThreadId();
QThreadthread;
Objectobj;
Dummydummy;
obj.moveToThread(&thread);
QObject::connect(&dummy,SIGNAL(sig()),&obj,SLOT(slot()));
thread.start();
dummy.emitsig();
}