Qt中的多線程編程


 

 

 QThread編程示例

class MyThread: public QThread   //創建線程類
{ protected: void run()   //線程入口函數
 { for(int i=0; i<5; i++) { qDebug() << objectName() << ":" << i; sleep(1)  //暫停1s
 } } };

多線程編程初探

實例1:

#include <QCoreApplication> #include <QThread> #include <QDebug>

class MyThread : public QThread { protected: void run() { qDebug() << objectName() << " : " << "run() begin"; for(int i=0; i<5; i++) { qDebug() << objectName() << ": " << i; sleep(1); } qDebug() << objectName() << " : " << "run() end"; } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << "main() begin"; MyThread t; t.setObjectName("t"); t.start(); //創建一個線程,並執行線程體run函數
 qDebug() << "main() end"; return a.exec(); }

 

示例中的主線程將先於子線程結束,所有線程都結束后,進程結束

 實例2

#include <QCoreApplication> #include <QThread> #include <QDebug>

class MyThread : public QThread { protected: void run() { qDebug() << objectName() << " : " << "run() begin"; for(int i=0; i<5; i++) { qDebug() << objectName() << ": " << i; sleep(1); } qDebug() << objectName() << " : " << "run() end"; } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << "main() begin"; MyThread t; t.setObjectName("t"); t.start(); //創建一個線程,並執行線程體run函數
 MyThread tt; tt.setObjectName("tt"); tt.start(); for(int i=0; i<100000; i++) { for(int j=0; j<10000; j++) { } } qDebug() << "main() end"; return a.exec(); }

第一次運行結果:

 

 第二次運行結果

 

 從上面的運行結果看,每次運行結果都不同。

在主線程中創建的兩個子線程是並行執行的,這兩個線程間沒有交互,各自執行。這就是線程間的並行性

 重要注意:

在工程開發中terminate是禁止使用的,terminate會使得操作系統暴力終止線程,而不考慮數據的完整性、資源釋放等問題。

問題:如何在代碼中優雅的終止線程

解決方案思路:

-run函數執行結束是優雅終止線程的唯一方式

-在線程類中增加標識變量m_toStop(volatile bool)每次都需要從內存中讀取,不需要編譯器做任何的優化。

-通過m_toStop的值判斷是否需要從run函數返回

class Solution : public QThread { protected: volatile bool m_toStop; void run(); public: Solution() { m_toStop = false; } void stop() { m_toStop = true; } }; void Solution::run() { while(!m_toStop) { //do task } }

首先看一下暴力終止線程的例子:

#include <QCoreApplication> #include <QThread> #include <QDebug>

class MyThread : public QThread { protected: void run() { qDebug() << objectName() << " : " << "run() begin"; for(int i=0; i<20; i++) { qDebug() << objectName() << ": " << i; msleep(500); } qDebug() << objectName() << " : " << "run() end"; } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << "main() begin"; MyThread t; t.setObjectName("t"); t.start(); //創建一個線程,並執行線程體run函數

    for(int i=0; i<100000; i++) { for(int j=0; j<10000; j++) { } } t.terminate(); qDebug() << "main() end"; return a.exec(); }

 在子線程中需要執行20次的,但當使用了terminate()暴力終止線程時,該線程出現了非正常死亡,該種方式不安全,也不優雅。

下面看一個暴力終止一個線程,帶來內存泄露的問題。

#include <QCoreApplication> #include <QThread> #include <QDebug>

class MyThread : public QThread { protected: void run() { qDebug() << objectName() << " : " << "run() begin"; int* p = new int[10000]; for(int i=0; i<20; i++) { qDebug() << objectName() << ": " << i; msleep(500); }  delete[] p; qDebug() << objectName() << " : " << "run() end"; } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << "main() begin"; MyThread t; t.setObjectName("t"); t.start(); //創建一個線程,並執行線程體run函數

    for(int i=0; i<100000; i++) { for(int j=0; j<10000; j++) { } } t.terminate(); qDebug() << "main() end"; return a.exec(); }

在子線程中,申請了一片堆空間,定義了10000個int型的數據。我們知道,堆空間只要申請了,就必須釋放。但是上面這個程序釋放了嗎?看樣子是真的釋放了,但事實真的如此嗎?看一下打印結果:

 

 從打印結果看,for循環只是運行了17次,就說明該子線程沒有運行完,該線程就被暴力終止了。因此delete[] p肯定沒有執行,申請了堆空間,沒有被釋放,那么將會產生內存泄露。

下面來看一下優雅的結束線程

#include <QCoreApplication> #include <QThread> #include <QDebug>

class MyThread : public QThread { protected: volatile bool m_toStop; void run() { qDebug() << objectName() << " : " << "run() begin"; int* p = new int[10000]; for(int i=0; (!m_toStop)&&(i<20); i++) { qDebug() << objectName() << ": " << i; msleep(500); } delete[] p; qDebug() << objectName() << " : " << "run() end"; } public: MyThread() { m_toStop = false; } void stop() { m_toStop = true; } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << "main() begin"; MyThread t; t.setObjectName("t"); t.start(); //創建一個線程,並執行線程體run函數

    for(int i=0; i<100000; i++) { for(int j=0; j<10000; j++) { } } t.stop(); qDebug() << "main() end"; return a.exec(); }

使用t.stop優雅的結束線程,從打印結果看,t run() end被執行了,說明delete[] p被執行了,申請的堆空間被釋放了。(注意,即使20次for循環沒有被執行完,但是申請的堆空間被釋放,達到了我們的要求)。

這種解決方案並不只適用Qt開發中,在其他的平台開發中,只要涉及多線程都可以考慮這種解決方案。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM