淺談 Qt 線程類 起點學習
淺談 Qt 多線程類 起點學習是本文要介紹的內容,不多說,先來看內容。由于Qt的跨平臺特性,QThread成功隱藏了所有在不同操作系統里使用線程的平臺相關性代碼。
POINT 1:QThread類的實例與普通類的實例沒什么不同,只是運行著的run()函數會不同。
例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對象的實例mythread是屬于創建它的線程(線程A,即MDialog所在的線程)的,mythread的所有程序代碼與數據都放在與MDialog相同的空間中.這時的mythread,就像任何普通的自己定義的類的實例一樣.但是在調用mythread->start()之后,mythread的run()函數中的代碼會在新的線程(線程B)中執行.在run()函數中聲明的變量\實例化的對象,都屬于線程B.
但是mythread的所有代碼,都還在存儲在線程A中,只是run()函數的"執行"是在線程B中.在MDialog中,使用mythread->foo();foo()是在線程A中執行的.在MDialog中使用connect(this, SIGNAL(sigDialogSignal()), mythread, SLOT(slotThreadSlot()));
當emit sigDialogSignal()時,是會在MDialog所在的線程A中執行的.因為mythread與MDialog同屬于一個線程, 這時thread可以看做一個普通類的實例.另外,因為connect函數的連接方式默認是自動連接,而對同屬于一個純種的兩個對象,自動連接會使用直接連接,即slot在發出signal的線程中立即執行.
例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()<<"==============================";
- }
運行后出現:
- ...
- ...
- ---------9
- ==============================================================
- ---------9
- ...
- ...
不能誤以為:在一個QThread類的派生類中,run()函數中的語句在運行時,可能被本線程定時器超時slot中斷. (錯誤)
事實上,slotPrint()在創建MThread的實例的線程中執行.
POINT 2:線程B中的對象要想接收線程A中的對象發來的signal, 必須進入exec(), 如在exec()前有死循環, 沒有進入exec(), 則線程B中的對象不會收到signal.
- void MThread::run()
- {
- while(1) {
- dosomething(); //此循環永不退出
- }
- exec(); //如果此事件循環不能進入,剛此線程不會收到任何signal
- }
POINT 3:線程A中的指針可指向線程B中創建的對象實例, 這個實例屬于線程B. 指針僅僅是一個地址, 而對象實例的變量/代碼等都屬于線程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所指向的對象屬于另一個線程.
例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這個指針屬于舊線程,但myTimer所指向的QTimer實例的實體在新的線程中,testFoo()會在新線程中執行,例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()也會在新線程中執行,例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()會在創建myTimer的老線程中執行.因為可以看到,mytimer和this(即mythread),都是在同一個線程中,只是在另一個線程中(run()),做了connect操作.
要注意的是,在線程B中啟動線程A中的一個定時器,不能使用myTimer.start(),這樣啟動不了定時器.而應使用signal來觸發start()這個slot.
POINT 5:slot不會中斷同線程中的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()函數運行完之后才會退出,說明slot不會中斷slot,一個slot在執行完之后才會執行下一個slot.
注意:slotPrint()在創建MThread實例的線程中執行.而不是使用thread->start()創建出的那個線程,例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()會在兩個不同的線程中執行.
小結:淺談 Qt 多線程類 起點學習的內容介紹完了,希望本文對你有所幫助。更多內容請參考編輯推薦。