您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關C/C++ Qt QThread線程組件的具體使用是怎樣的,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
QThread庫是QT中提供的跨平臺多線程實現方案,使用時需要繼承QThread這個基類,并重寫實現內部的Run方法,由于該庫是基本庫,默認依賴于QtCore.dll
這個基礎模塊,在使用時無需引入其他模塊.
QThread庫提供了跨平臺的多線程管理方案,通常一個QThread對象管理一個線程,在使用是需要從QThread類繼承并重寫內部的Run方法,并在Run方法內部實現多線程代碼.
#include <QCoreApplication> #include <iostream> #include <QThread> class MyThread: public QThread { protected: volatile bool m_to_stop; protected: // 線程函數必須使用Run作為開始 void run() { for(int x=0; !m_to_stop && (x <10); x++) { msleep(1000); std::cout << objectName().toStdString() << std::endl; } } public: MyThread() { m_to_stop = false; } // 用于設置結束符號為真 void stop() { m_to_stop = true; } // 輸出線程運行狀態 void is_run() { std::cout << "Thread Running = " << isRunning() << std::endl; } // 輸出線程完成狀態(是否結束) void is_finish() { std::cout << "Thread Finished = " << isFinished() << std::endl; } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 定義線程數組 MyThread thread[10]; // 設置線程對象名字 for(int x=0;x<10;x++) { thread[x].setObjectName(QString("thread => %1").arg(x)); } // 批量調用run執行 for(int x=0;x<10;x++) { thread[x].start(); thread[x].is_run(); thread[x].isFinished(); } // 批量調用stop關閉 for(int x=0;x<10;x++) { thread[x].wait(); thread[x].stop(); thread[x].is_run(); thread[x].is_finish(); } return a.exec(); }
線程在執行前可以通過調用MyThread中的自定義函數,并在函數內實現參數賦值,實現線程傳參操作.
#include <QCoreApplication> #include <iostream> #include <QThread> class MyThread: public QThread { protected: int m_begin; int m_end; int m_result; void run() { m_result = m_begin + m_end; } public: MyThread() { m_begin = 0; m_end = 0; m_result = 0; } // 設置參數給當前線程 void set_value(int x,int y) { m_begin = x; m_end = y; } // 獲取當前線程名 void get_object_name() { std::cout << "this thread name => " << objectName().toStdString() << std::endl; } // 獲取線程返回結果 int result() { return m_result; } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); MyThread thread[3]; // 分別將不同的參數傳入到線程函數內 for(int x=0; x<3; x++) { thread[x].set_value(1,2); thread[x].setObjectName(QString("thread -> %1").arg(x)); thread[x].start(); } // 等待所有線程執行結束 for(int x=0; x<3; x++) { thread[x].get_object_name(); thread[x].wait(); } // 獲取線程返回值并相加 int result = thread[0].result() + thread[1].result() + thread[2].result(); std::cout << "sum => " << result << std::endl; return a.exec(); }
QMutex類是基于互斥量的線程同步鎖,該鎖lock()
鎖定與unlock()
解鎖必須配對使用,線程鎖保證線程間的互斥,利用線程鎖能夠保證臨界資源的安全性.
線程鎖解決的問題: 多個線程同時操作同一個全局變量,為了防止資源的無序覆蓋現象,從而需要增加鎖,來實現多線程搶占資源時可以有序執行.
臨界資源(Critical Resource): 每次只允許一個線程進行訪問 (讀/寫)的資源.
線程間的互斥(競爭): 多個線程在同一時刻都需要訪問臨界資源.
一般性原則: 每一個臨界資源都需要一個線程鎖進行保護.
#include <QCoreApplication> #include <iostream> #include <QThread> #include <QMutex> static QMutex g_mutex; // 線程鎖 static QString g_store; // 定義全局變量 class Producer : public QThread { protected: void run() { int count = 0; while(true) { // 加鎖 g_mutex.lock(); g_store.append(QString::number((count++) % 10)); std::cout << "Producer -> "<< g_store.toStdString() << std::endl; // 釋放鎖 g_mutex.unlock(); msleep(900); } } }; class Customer : public QThread { protected: void run() { while( true ) { g_mutex.lock(); if( g_store != "" ) { g_store.remove(0, 1); std::cout << "Curstomer -> "<< g_store.toStdString() << std::endl; } g_mutex.unlock(); msleep(1000); } } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Producer p; Customer c; p.setObjectName("producer"); c.setObjectName("curstomer"); p.start(); c.start(); return a.exec(); }
QMutexLocker是在QMutex基礎上簡化版的線程鎖,QMutexLocker會保護加鎖區域,并自動實現互斥量的鎖定和解鎖操作,可以將其理解為是智能版的QMutex鎖,該鎖只需要在上方代碼中稍加修改即可.
#include <QMutex> #include <QMutexLocker> static QMutex g_mutex; // 線程鎖 static QString g_store; // 定義全局變量 class Producer : public QThread { protected: void run() { int count = 0; while(true) { // 增加智能線程鎖 QMutexLocker Locker(&g_mutex); g_store.append(QString::number((count++) % 10)); std::cout << "Producer -> "<< g_store.toStdString() << std::endl; msleep(900); } } };
互斥鎖存在一個問題,每次只能有一個線程獲得互斥量的權限,如果在程序中有多個線程來同時讀取某個變量,那么使用互斥量必須排隊,效率上會大打折扣,基于QReadWriteLock
讀寫模式進行代碼段鎖定,即可解決互斥鎖存在的問題.
該鎖允許用戶以同步讀lockForRead()
或同步寫lockForWrite()
兩種方式實現保護資源,但只要有一個線程在以寫的方式操作資源,其他線程也會等待寫入操作結束后才可繼續讀資源.
#include <QCoreApplication> #include <iostream> #include <QThread> #include <QMutex> #include <QReadWriteLock> static QReadWriteLock g_mutex; // 線程鎖 static QString g_store; // 定義全局變量 class Producer : public QThread { protected: void run() { int count = 0; while(true) { // 以寫入方式鎖定資源 g_mutex.lockForWrite(); g_store.append(QString::number((count++) % 10)); // 寫入后解鎖資源 g_mutex.unlock(); msleep(900); } } }; class Customer : public QThread { protected: void run() { while( true ) { // 以讀取方式寫入資源 g_mutex.lockForRead(); if( g_store != "" ) { std::cout << "Curstomer -> "<< g_store.toStdString() << std::endl; } // 讀取到后解鎖資源 g_mutex.unlock(); msleep(1000); } } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Producer p1,p2; Customer c1,c2; p1.setObjectName("producer 1"); p2.setObjectName("producer 2"); c1.setObjectName("curstomer 1"); c2.setObjectName("curstomer 2"); p1.start(); p2.start(); c1.start(); c2.start(); return a.exec(); }
信號量是特殊的線程鎖,信號量允許N個線程同時訪問臨界資源,通過acquire()
獲取到指定資源,release()
釋放指定資源.
#include <QCoreApplication> #include <iostream> #include <QThread> #include <QSemaphore> const int SIZE = 5; unsigned char g_buff[SIZE] = {0}; QSemaphore g_sem_free(SIZE); // 5個可生產資源 QSemaphore g_sem_used(0); // 0個可消費資源 // 生產者生產產品 class Producer : public QThread { protected: void run() { while( true ) { int value = qrand() % 256; // 若無法獲得可生產資源,阻塞在這里 g_sem_free.acquire(); for(int i=0; i<SIZE; i++) { if( !g_buff[i] ) { g_buff[i] = value; std::cout << objectName().toStdString() << " --> " << value << std::endl; break; } } // 可消費資源數+1 g_sem_used.release(); sleep(2); } } }; // 消費者消費產品 class Customer : public QThread { protected: void run() { while( true ) { // 若無法獲得可消費資源,阻塞在這里 g_sem_used.acquire(); for(int i=0; i<SIZE; i++) { if( g_buff[i] ) { int value = g_buff[i]; g_buff[i] = 0; std::cout << objectName().toStdString() << " --> " << value << std::endl; break; } } // 可生產資源數+1 g_sem_free.release(); sleep(1); } } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Producer p1; Customer c1; p1.setObjectName("producer"); c1.setObjectName("curstomer"); p1.start(); c1.start(); return a.exec(); }
上述就是小編為大家分享的C/C++ Qt QThread線程組件的具體使用是怎樣的了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。