一、历史的痕迹
1、注意
(1)、面向对象的程序设计实践的早期工程中习惯于通过继承的方式扩展系统的功能
2、现代软件架构技术
(1)、尽量使用组合的方式实现系统功能
(2)、代码中仅体现需求中的继承关系
3、通过继承方式实现新的线程类的事实
(1)、线程子类仅保护void run()函数不同,接口部分完全相同
4、结论
(1)、通过继承的方式实现多线程没有任何实际意义(只是为了得到线程入口而已)
(2)、QThread对应于操作系统中的线程
(3)、QThread用于充当一个线程操作的集合
(4)、应该提供灵活的方式指定线程入口函数
(5)、尽量避免void run()函数
二、QThread类的改进(run()已经不单单是纯虚函数)
1、解决方案:信号与槽
(1)、在类中定义一个槽函数void tmain()作为线程入口函数
(2)、在类中定义一个QThread成员对象m_thread
(3)、改变当前线程的依附性到m_thread
(4)、连接m_thread的start()信号到tmain()
#ifndef ASYNTHREAD_H #define ASYNTHREAD_H #include <QObject> #include <QThread> class AsynThread : public QObject { Q_OBJECT public: static AsynThread* NewInstance(QObject *parent = 0); void start(); void terminate(); private: QThread* m_thread; QThread* pThread; explicit AsynThread(QObject *parent = 0); ~AsynThread(); protected slots: void tmain(); }; #endif // ASYNTHREAD_H
#include "AsynThread.h" #include <QDebug> AsynThread::AsynThread(QObject *parent) : QObject(parent) { m_thread = new QThread();//记得是在堆空间上创建线程对象 pThread = QThread::currentThread();//保存调用deleteLater的线程,以便等下返回调用deleteLater线程 moveToThread(m_thread); connect(m_thread, SIGNAL(started()), this, SLOT(tmain())); } AsynThread* AsynThread::NewInstance(QObject *parent) { return new AsynThread(parent); } void AsynThread::tmain() { qDebug() << "void SynThread::tmain() tid=" << QThread::currentThreadId(); for(int i=0; i<10; i++) { qDebug() << "void SynThread::tmain() i=" << i; } qDebug() << "void SynThread::tmain() end"; m_thread->quit();//为了析构函数中删除成员对象m_thread moveToThread(pThread); deleteLater();//删除当前对象,即调用这个函数的对象,则析构函数也是在那里被调用 } void AsynThread::start() { m_thread->start(); } void AsynThread::terminate() { m_thread->terminate(); } AsynThread::~AsynThread() { delete m_thread; qDebug() << "AsynThread::~SynThread() tid=" << QThread::currentThreadId(); }
#ifndef MYTHREAD_H #define MYTHREAD_H #include <QObject> #include <QThread> class SynThread : public QObject { Q_OBJECT public: explicit SynThread(QObject *parent = 0); void start(); void terminate(); ~SynThread(); protected slots: void tmain(); private: QThread m_thread; }; #endif // MYTHREAD_H
#include "SynThread.h" #include <QDebug> SynThread::SynThread(QObject *parent) : QObject(parent) { moveToThread(&m_thread); connect(&m_thread, SIGNAL(started()), this, SLOT(tmain())); } void SynThread::tmain() { qDebug() << "void SynThread::tmain() tid=" << QThread::currentThreadId(); for(int i=0; i<10; i++) { qDebug() << "void SynThread::tmain() i=" << i; } qDebug() << "void SynThread::tmain() end"; } void SynThread::start() { m_thread.start(); } void SynThread::terminate() { m_thread.terminate(); } SynThread::~SynThread() { m_thread.wait(); }
#include <QtCore/QCoreApplication> #include "SynThread.h" #include "AsynThread.h" void synthread() { SynThread t; t.start(); } void asynthread() { AsynThread* at = AsynThread::NewInstance(); at->start(); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); //synthread(); asynthread(); return a.exec(); }
//上面的异步型仍有bug:m_thread.quit()不一定立即退出,而是向子线程的事件队列中加入一个退出事件
//本例中如果子线程先退出则运行无误,但如果是父线程先调用析构函数则会产生竞争问题
//解决办法:
关于deleteLater的理解
(1)、内部实现
void QObject::deleteLater()
{
QCoreApplication::postEvent(this, new QEvent(QEvent::DeferredDelete));
}
(2)、说明在哪个对象中调用就会往该对象依附的线程的事件队列中加入事件
(3)、调用deletLater的对象依赖于哪个线程,删除工作就在哪个线程完成
(4)、一般来说都会返回原来调用deleteLater的线程
三、小结
(1)、早期的Qt版本只能通过继承的方式创建线程
(2)、现代软件提倡以组合的方式代替继承
(3)、QThread应该作为线程的操作集合而使用
(4)、可以通过信号与槽的机制灵活指定线程入口函数