我们在使用线程的时候,可以将一个类派生自QObject,然后实现相应的signal/slot,通过调用movetothread函数来使槽执行在新的线程里面,而不是每次都要重新派生QThread,并且派生QThread函数的另外一个不好的地方是只有run函数内部的代码才会执行在新线程里面,相比起来,派生QObject并使用movetothread函数更具有灵活性。
moveToThread对比传统子类化Qthread更灵活,仅需要把你想要执行的代码放到槽,movetothread这个object到线程,然后拿一个信号连接到这个槽,当需要运行线程时发送该信号就可以让这个槽函数在线程里执行。
注意:上述说的object对应的类如果有多个槽,且信号是其他类的信号,则object类的槽将会被移到线程执行,但是如果object类的其中一个槽是阻塞的,比如说有一个while循环且不退出,此时发信号后,只有本槽会被调用且一直运行,其他的槽会一直调用不到,必须等本槽退出后,其他槽才会调用到。(此处可以从connect最后一个参数看出,为队列连接时,当控制权回到接受者所依附线程的事件循环时,槽函数被调用,没有获取到事件循环的控制权,槽函数会一直不被调用)此种方法适合有多个槽要放到线程里面执行,并且这多个槽都不会阻塞的情况。
如果有一个槽需要长时间阻塞,并且还有其他多个槽,此种情况需要本类继承自QThread类,然后在run里面运行需要阻塞的槽,如while循环长时间不退出的槽,将其他不阻塞的槽定义为普通槽,此时在其他类发的信号本类的其他槽能被调用。
QThread 使用探讨
http://blog.youkuaiyun.com/chinabinlang/article/details/35988801
一种使用QThread线程的新方法QObject::moveToThread
http://blog.youkuaiyun.com/sydnash/article/details/7425947
http://blog.youkuaiyun.com/zhangbinsijifeng/article/details/47783599
二、使用moveToThread(),因为在Qt4.3(包括)之前,run 是虚函数,必须子类化QThread来实现run函数。而从Qt4.4开始run() 默认调用 QThread::exec() ,线程在调用quit()、exit()或terminat()之前不会退出。这样一来不需要子类化 QThread 了,只需要子类化一个 QObject 就够了,这正是被 Bradley T. Hughes(Qt的开发人员)推荐的方法。怎么用呢,使用connect()!!所以下边要了解信号和槽的关系。等下会分析下connnect的第五个参数。对了,如果moveToThread里执行的函数没执行完,你是无法通过quit来结束的,必须使用第一种方法:最歹毒的一招mthread->terminate()强制退出。
class MyMoveToThreadFunc :public QObject
{
Q_OBJECT
public:
void showObjectThreadID()
{
qDebug()<<"# MyMoveToThreadFunc thread id = "<<QThread::currentThreadId();
}
signals:
void again();
public slots:
void slotOfThread()
{
qDebug()<<" MyMoveToThreadFunc slot thread id = "<<QThread::currentThreadId();
emit again();
}
};
class MyTry:public QObject
{
Q_OBJECT
public:
MyTry();
QThread *mThread;
MyMoveToThreadFunc *mFunc;
};
MyTry::MyTry()
{
mThread = new QThread();
qDebug()<<"main thread id = "<<QThread::currentThreadId();
mFunc = new MyMoveToThreadFunc();
mFunc->moveToThread(mThread);</span>
QObject::connect(mThread,SIGNAL(started()),mFunc,SLOT(slotOfThread()));//slot将会在mThread中运行
mFunc->showObjectThreadID()//在主程序运行。
mThread->start();//启动线程
}
如果要实现事件循环怎么办?一样,随便找个信号连接到slotOfThread(),循环发送就行了。例如,你重载mThread,让他以第一种循环循环发出信号给mFunc连接也行。记住,直接在主程序调用mFunc的函数,函数还是会是在主程序运行。