一文帶你了解Qt多線程的實(shí)現(xiàn)方式
QThread的run方法
一個(gè)QThread對(duì)象管理一個(gè)線程,一般從QThread繼承一個(gè)自定義的類,并實(shí)現(xiàn)run方法,在run函數(shù)中實(shí)現(xiàn)線程需要完成的任務(wù)。QThread自身定義了started() 和finish()兩個(gè)信號(hào),started() 信號(hào)是在開始執(zhí)行之前發(fā)射,finished()信號(hào)是在線程就要結(jié)束時(shí)發(fā)射。
class WorkerThread : public QThread { Q_OBJECT void run() override { // TODO emit sigMsg(result); } signals: void sigMsg(const QString &s); }; void main() { WorkerThread *workerThread = new WorkerThread(this); workerThread->start(); }
特點(diǎn)
1、優(yōu)點(diǎn):可以通過(guò)信號(hào)槽與外界進(jìn)行通信。
2、缺點(diǎn):每次新建一個(gè)線程都需要繼承QThread,實(shí)現(xiàn)一個(gè)新類,使用不太方便。
要自己進(jìn)行資源管理,線程釋放和刪除。并且頻繁的創(chuàng)建和釋放會(huì)帶來(lái)比較大的內(nèi)存開銷。
3、適用場(chǎng)景:QThread適用于那些常駐內(nèi)存的任務(wù)。
QObject的moveToThread
創(chuàng)建一個(gè)繼承QObject的類MyThread,把要執(zhí)行的計(jì)算放到一個(gè)函數(shù)中doWork,然后new一個(gè)Qthread,并把創(chuàng)建的myThread類movetothread到創(chuàng)建好的子線程中,然后start子線程,這樣就實(shí)現(xiàn)了一個(gè)子線程。這里一定要通過(guò)信號(hào)去調(diào)用doWork函數(shù)。
class MyThread:public QObject { Q_OBJECT public slots: void doWork(){ int i=0; while(i<4){ // ToDo qDebug()<<QThread::currentThread()<<" "<<i++; } } ? ? }; ? class MyTest :public QObject { Q_OBJECT QThread workerThread; public: MyTest(){ MyThread* myThread = new MyThread(); // 這個(gè)任務(wù)函數(shù)不能有父對(duì)象,有父對(duì)象時(shí)不可以moveToThread myThread->moveToThread(&workerThread); workerThread.start(); connect(this,&MyTest::active,myThread,&MyThread::doWork); // 一定要通過(guò)槽函數(shù)去調(diào)用對(duì)應(yīng)的函數(shù),否則還是在主線程 } ~MyTest(){ workerThread.quit(); } signals: void active(); }; ? MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { qDebug()<<QThread::currentThread(); ui->setupUi(this); MyTest* t = new MyTest(); t->active(); QThread::sleep(3000); t->deleteLater(); }
特點(diǎn)
一定要通過(guò)槽函數(shù)的形式去調(diào)用函數(shù),要注意!你創(chuàng)建的QThread對(duì)象實(shí)例,仍然存活在主線程上,而非子線程。所以如果你直接調(diào)用其中的函數(shù),那么還是在主線程上運(yùn)行的。該方法并不是線程安全的。
QRunnalble的run
繼承Qrunnable,并重寫run虛函數(shù),使用QThreadPool啟動(dòng)線程
class Runnable:public QRunnable { public: Runnable(); ~Runnable(); void run(); }; Runnable::Runnable():QRunnable() { } Runnable::~Runnable() { cout<<"~Runnable()"<<endl; } void Runnable::run() { cout<<"Runnable::run()thread :"<<QThread::currentThreadId()<<endl; cout<<"dosomething ...."<<endl; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); cout<<"mainthread :"<<QThread::currentThreadId()<<endl; Runnable runObj; QThreadPool::globalInstance()->start(&runObj); returna.exec(); }
特點(diǎn)
1,無(wú)需手動(dòng)釋放資源,QThreadPool啟動(dòng)線程執(zhí)行完成后會(huì)自動(dòng)釋放。
2,不能使用信號(hào)槽與外界通信。
3,QRunnable適用于線程任務(wù)量比較大,需要頻繁創(chuàng)建線程。QRunnable能有效減少內(nèi)存開銷。
QtConcurrent的run
使用QtConcurrent編寫的程序會(huì)根據(jù)可用的處理器內(nèi)核數(shù)自動(dòng)調(diào)整使用的線程數(shù)。QtConcurrent::run能夠方便快捷的將任務(wù)丟到子線程中去執(zhí)行,無(wú)需繼承任何類,也不需要重寫函數(shù),使用非常簡(jiǎn)單。通過(guò)QtConcurrent::run()返回的QFuture不支持取消、暫停,返回的QFuture只能用于查詢函數(shù)的運(yùn)行/完成狀態(tài)和返回值。
函數(shù)原型:
QFuture<T> QtConcurrent::run(Function function, ...) QFuture<T> QtConcurrent::run(QThreadPool *pool, Function function, ...)
使用方式
QtConcurrent::run([=]() { // TODO });
線程同步
基于QMutex互斥同步
QMutex的目的是保護(hù)一個(gè)對(duì)象、數(shù)據(jù)結(jié)構(gòu)或者代碼段,所以同一時(shí)間只有一個(gè)線程可以訪問它。如果使用Mutex鎖那么多個(gè)線程在訪問一段代碼的時(shí)候是存在阻塞的,一個(gè)執(zhí)行完畢下一個(gè)線程才會(huì)繼續(xù)執(zhí)行
lock():試圖鎖定互斥量。如果另一個(gè)線程已經(jīng)鎖定這個(gè)互斥量,那么這次調(diào)用將阻塞直到那個(gè)線程把它解鎖。
unlock():進(jìn)行解鎖
tryLock():試圖鎖定互斥量。如果鎖被得到,這個(gè)函數(shù)返回真。如果另一個(gè)進(jìn)程已經(jīng)鎖定了這個(gè)互斥量,這個(gè)函數(shù)返回假,而不是一直等到這個(gè)鎖可用為止
QMutex mutex; void DebugInfo() { mutex.lock(); qDebug("ABC"); qDebug("DEF"); mutex.unlock(); }
基于QReadWriteLock的線程同步
一種讀寫鎖,用于保護(hù)可以進(jìn)行讀寫訪問的資源。這種索允許多個(gè)線程同時(shí)進(jìn)行只讀訪問,但是一旦一個(gè)線程想要寫入資源,則必須阻止所有其他線程,直到寫入完成。
QReadWriteLock lock; void ReaderThread::run() { ... lock.lockForRead(); read_file(); lock.unlock(); ... } void WriterThread::run() { ... lock.lockForWrite(); write_file(); lock.unlock(); ... }
void lockForRead():鎖定讀取鎖。如果另一個(gè)線程已鎖定以進(jìn)行寫入,則此函數(shù)將阻塞當(dāng)前線程。如果線程已經(jīng)鎖定寫入,則無(wú)法鎖定讀取。void lockForWrite():鎖定寫入鎖。如果另一個(gè)線程(包括當(dāng)前線程)已鎖定讀取或?qū)懭?,則此函數(shù)將阻塞當(dāng)前線程。如果線程已經(jīng)為讀取而鎖定,則不會(huì)為寫入而鎖定。
基于QWaitCondition的線程同步
QWaitCondition 允許線程在某些情況發(fā)生時(shí)喚醒另外的線程。一個(gè)或多個(gè)線程可以阻塞等待一QWaitCondition ,用wakeOne()或wakeAll()設(shè)置一個(gè)條件。wakeOne()隨機(jī)喚醒一個(gè),wakeAll()喚醒所有
const int DataSize = 100000; const int BufferSize = 8192; char buffer[BufferSize]; QWaitCondition bufferNotEmpty; QWaitCondition bufferNotFull; QMutex mutex; int numUsedBytes = 0; class Producer : public QThread { public: void run(); }; void Producer::run() { qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); for (int i = 0; i < DataSize; ++i) { mutex.lock(); if (numUsedBytes == BufferSize) bufferNotFull.wait(&mutex); mutex.unlock(); buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4]; mutex.lock(); ++numUsedBytes; bufferNotEmpty.wakeAll(); mutex.unlock(); } } class Consumer : public QThread { public: void run(); }; void Consumer::run() { for (int i = 0; i < DataSize; ++i) { mutex.lock(); if (numUsedBytes == 0) bufferNotEmpty.wait(&mutex); mutex.unlock(); fprintf(stderr, "%c", buffer[i % BufferSize]); mutex.lock(); --numUsedBytes; bufferNotFull.wakeAll(); mutex.unlock(); } fprintf(stderr, "\n"); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); Producer producer; Consumer consumer; producer.start(); consumer.start(); producer.wait(); consumer.wait(); return 0; }
到此這篇關(guān)于一文帶你了解Qt多線程的實(shí)現(xiàn)方式的文章就介紹到這了,更多相關(guān)Qt多線程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Visual Studio 2010/2013編譯V8引擎步驟分享
這篇文章主要介紹了使用Visual Studio 2013編譯V8引擎步驟分享,需要的朋友可以參考下2015-08-08C語(yǔ)言之實(shí)現(xiàn)字符串小寫變大寫的實(shí)例
這篇文章主要介紹了C語(yǔ)言之實(shí)現(xiàn)字符串小寫變大寫的實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-05-05設(shè)計(jì)模式中的備忘錄模式解析及相關(guān)C++實(shí)例應(yīng)用
這篇文章主要介紹了設(shè)計(jì)模式中的備忘錄模式解析及相關(guān)C++實(shí)例應(yīng)用,備忘錄模式也經(jīng)常被用來(lái)在命令模式中維護(hù)可以撤銷(Undo)操作的狀態(tài),需要的朋友可以參考下2016-03-03C語(yǔ)言創(chuàng)建windows窗口實(shí)例
這篇文章主要介紹了C語(yǔ)言創(chuàng)建windows窗口實(shí)例,本文直接給出實(shí)現(xiàn)代碼,同時(shí)講解了編碼的步驟,需要的朋友可以參考下2015-04-04C語(yǔ)言強(qiáng)制類型轉(zhuǎn)換規(guī)則實(shí)例詳解
強(qiáng)制類型轉(zhuǎn)換是把變量從一種類型轉(zhuǎn)換為另一種數(shù)據(jù)類型,下面這篇文章主要給大家介紹了關(guān)于C語(yǔ)言強(qiáng)制類型轉(zhuǎn)換的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06