淺談 Qt 線程類 起點(diǎn)學(xué)習(xí)
淺談 Qt 多線程類 起點(diǎn)學(xué)習(xí)是本文要介紹的內(nèi)容,不多說,先來看內(nèi)容。由于Qt的跨平臺(tái)特性,QThread成功隱藏了所有在不同操作系統(tǒng)里使用線程的平臺(tái)相關(guān)性代碼。
POINT 1:QThread類的實(shí)例與普通類的實(shí)例沒什么不同,只是運(yùn)行著的run()函數(shù)會(huì)不同。
例1:
- class MThread :public QThread
 - {
 - public:
 - MThread();
 - ~MThread();
 - void run();
 - void foo();
 - ...
 - };
 - class MDialog :public QDialog
 - {
 - ...
 - MThread *mythread;
 - };
 - MDialog::MDialog()
 - {
 - mythread = new MThread;
 - ...
 - }
 
需要注意的是,在QT中,QThread對象的實(shí)例mythread是屬于創(chuàng)建它的線程(線程A,即MDialog所在的線程)的,mythread的所有程序代碼與數(shù)據(jù)都放在與MDialog相同的空間中.這時(shí)的mythread,就像任何普通的自己定義的類的實(shí)例一樣.但是在調(diào)用mythread->start()之后,mythread的run()函數(shù)中的代碼會(huì)在新的線程(線程B)中執(zhí)行.在run()函數(shù)中聲明的變量\實(shí)例化的對象,都屬于線程B.
但是mythread的所有代碼,都還在存儲(chǔ)在線程A中,只是run()函數(shù)的"執(zhí)行"是在線程B中.在MDialog中,使用mythread->foo();foo()是在線程A中執(zhí)行的.在MDialog中使用connect(this, SIGNAL(sigDialogSignal()), mythread, SLOT(slotThreadSlot()));
當(dāng)emit sigDialogSignal()時(shí),是會(huì)在MDialog所在的線程A中執(zhí)行的.因?yàn)閙ythread與MDialog同屬于一個(gè)線程, 這時(shí)thread可以看做一個(gè)普通類的實(shí)例.另外,因?yàn)閏onnect函數(shù)的連接方式默認(rèn)是自動(dòng)連接,而對同屬于一個(gè)純種的兩個(gè)對象,自動(dòng)連接會(huì)使用直接連接,即slot在發(fā)出signal的線程中立即執(zhí)行.
例2:
- #include "mthread.h"
 - #include <QDebug>
 - MThread::MThread(QObject *parent)
 - : QThread(parent)
 - {
 - myTimer.start(1);
 - connect(&myTimer, SIGNAL(timeout()), this, SLOT(slotPrint()));
 - }
 - MThread::~MThread()
 - {
 - }
 - void MThread::run()
 - {
 - for (int i = 0; i < 100; ++i) {
 - for (int j = 0 ; j < 10000; ++j) {
 - qDebug()<<"---------"<<i;
 - }
 - }
 - exec();
 - }
 - void MThread::slotPrint()
 - {
 - qDebug()<<"==============================";
 - }
 
運(yùn)行后出現(xiàn):
- ...
 - ...
 - ---------9
 - ==============================================================
 - ---------9
 - ...
 - ...
 
不能誤以為:在一個(gè)QThread類的派生類中,run()函數(shù)中的語句在運(yùn)行時(shí),可能被本線程定時(shí)器超時(shí)slot中斷. (錯(cuò)誤)
事實(shí)上,slotPrint()在創(chuàng)建MThread的實(shí)例的線程中執(zhí)行.
POINT 2:線程B中的對象要想接收線程A中的對象發(fā)來的signal, 必須進(jìn)入exec(), 如在exec()前有死循環(huán), 沒有進(jìn)入exec(), 則線程B中的對象不會(huì)收到signal.
- void MThread::run()
 - {
 - while(1) {
 - dosomething(); //此循環(huán)永不退出
 - }
 - exec(); //如果此事件循環(huán)不能進(jìn)入,剛此線程不會(huì)收到任何signal
 - }
 
POINT 3:線程A中的指針可指向線程B中創(chuàng)建的對象實(shí)例, 這個(gè)實(shí)例屬于線程B. 指針僅僅是一個(gè)地址, 而對象實(shí)例的變量/代碼等都屬于線程B.
例1:
- class MThread : public QThread
 - {
 - Q_OBJECT
 - public:
 - MThread(QObject *parent = 0);
 - ~MThread();
 - void run();
 - MPrint *mprint;
 - };
 - void MThread::run()
 - {
 - mprint = new MPrint;
 - exec();
 - }
 - //如此聲明,mprint所指向的對象屬于另一個(gè)線程.
 
例2:
- class MThread : public QThread
 - {
 - Q_OBJECT
 - public:
 - MThread(QObject *parent = 0);
 - ~MThread();
 - void run();
 - MPrint *mprint;
 - private:
 - QTimer *myTimer;
 - private slots:
 - void slotPrint();
 - void testFoo();
 - };
 - void MThread::run()
 - {
 - myTimer = new QTimer;
 - mprint = new MPrint;
 - myTimer->setInterval(100);
 - connect(myTimer, SIGNAL(timeout()), this, SLOT(testFoo()), Qt::DirectConnection);
 - QTimer::singleShot(0, myTimer,SLOT(start()));
 - exec();
 
上這樣寫run(),myTimer在run()中new,即myTimer這個(gè)指針屬于舊線程,但myTimer所指向的QTimer實(shí)例的實(shí)體在新的線程中,testFoo()會(huì)在新線程中執(zhí)行,例3:
- void MThread::run()
 - {
 - QTimer myTimer;
 - mprint = new MPrint;
 - myTimer.setInterval(100);
 - connect(&myTimer, SIGNAL(timeout()), this, SLOT(testFoo()), Qt::DirectConnection);
 - QTimer::singleShot(0, &myTimer,SLOT(start()));
 - //testFoo();
 - exec();
 - }
 
以上這樣寫run(),myTimer在run()中聲明,即myTimer屬于新的線程,testFoo()也會(huì)在新線程中執(zhí)行,例4:
- class MThread : public QThread
 - {
 - Q_OBJECT
 - public:
 - MThread(QObject *parent = 0);
 - ~MThread();
 - void run();
 - MPrint *mprint;
 - private:
 - QTimer myTimer;
 - private slots:
 - void slotPrint();
 - void testFoo();
 - };
 - void MThread::run()
 - {
 - mprint = new MPrint;
 - myTimer.setInterval(100);
 - connect(&myTimer, SIGNAL(timeout()), this, SLOT(testFoo()));
 - QTimer::singleShot(0, &myTimer,SLOT(start()));
 - //testFoo();
 - exec();
 - }
 
以上這樣寫run(),testFoo()會(huì)在創(chuàng)建myTimer的老線程中執(zhí)行.因?yàn)榭梢钥吹?mytimer和this(即mythread),都是在同一個(gè)線程中,只是在另一個(gè)線程中(run()),做了connect操作.
要注意的是,在線程B中啟動(dòng)線程A中的一個(gè)定時(shí)器,不能使用myTimer.start(),這樣啟動(dòng)不了定時(shí)器.而應(yīng)使用signal來觸發(fā)start()這個(gè)slot.
POINT 5:slot不會(huì)中斷同線程中的slot,例1:
- #include "mthread.h"
 - #include <QDebug>
 - MThread::MThread(QObject *parent)
 - : QThread(parent)
 - {
 - myTimer.start(1);
 - connect(&myTimer, SIGNAL(timeout()), this, SLOT(slotPrint()));
 - }
 - MThread::~MThread()
 - {
 - }
 - void MThread::run()
 - {
 - exec();
 - }
 - void MThread::slotPrint()
 - {
 - qDebug()<<"===========================";
 - for (int i = 0; i < 100; ++i) {
 - for (int j = 0 ; j < 10000; ++j) {
 - qDebug()<<"---------"<<i;
 - }
 - }
 - }
 
slotPrint()函數(shù)運(yùn)行完之后才會(huì)退出,說明slot不會(huì)中斷slot,一個(gè)slot在執(zhí)行完之后才會(huì)執(zhí)行下一個(gè)slot.
注意:slotPrint()在創(chuàng)建MThread實(shí)例的線程中執(zhí)行.而不是使用thread->start()創(chuàng)建出的那個(gè)線程,例2:
- #include "mthread.h"
 - #include <QDebug>
 - MThread::MThread(QObject *parent)
 - : QThread(parent)
 - {
 - myTimer.start(1);
 - connect(&myTimer, SIGNAL(timeout()), this, SLOT(slotPrint()));
 - }
 - MThread::~MThread()
 - {
 - }
 - void MThread::run()
 - {
 - testFoo();
 - exec();
 - }
 - void MThread::slotPrint()
 - {
 - qDebug()<<"=======================";
 - }
 - void MThread::testFoo()
 - {
 - for (int i = 0; i < 100; ++i) {
 - for (int j = 0 ; j < 10000; ++j) {
 - qDebug()<<"---------"<<i;
 - }
 - }
 - }
 
以上代碼中,slotPrint()與testFoo()會(huì)在兩個(gè)不同的線程中執(zhí)行.
小結(jié):淺談 Qt 多線程類 起點(diǎn)學(xué)習(xí)的內(nèi)容介紹完了,希望本文對你有所幫助。更多內(nèi)容請參考編輯推薦。















 
 
 
 
 
 
 