欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Qt線程QThread開啟和安全退出的實(shí)現(xiàn)

 更新時(shí)間:2023年06月07日 09:46:10   作者:Qt開發(fā)老杰  
本文主要介紹了Qt線程QThread開啟和安全退出的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1、線程開啟

Qt中,開啟子線程,一般有兩種方法:

a, 定義工作類worker:

worker繼承 QThread, 重寫run函數(shù),在主線程中實(shí)例化worker,把耗時(shí)工作放進(jìn)worker的run函數(shù)中完成,結(jié)束后,往主線程中發(fā)信號,傳遞參數(shù)即可。

注意:此worker的實(shí)例,只有run函數(shù)在子線程中執(zhí)行,worker的其他函數(shù),均在主線程中執(zhí)行。

如果子線程已經(jīng)start開啟,run函數(shù)尚未運(yùn)行完時(shí),再次start,此時(shí)子線程不會有任何操作,run函數(shù)不會被重新調(diào)用,會繼續(xù)執(zhí)行run函數(shù)。

b, 定義工作類worker:

worker繼承Qobject,在worker中完成耗時(shí)操作,并在主線程中 #include “worker.h”進(jìn)來,隨后,在主線程中New出幾個(gè)子線程QThread,使用moveToThread()函數(shù),把worker轉(zhuǎn)移進(jìn)入子線程,例如:

pWorker = new Worker;
pThread1 = new QThread;
pWorker->moveToThread(pThread1)

之后,再根據(jù)需求,看何時(shí)開啟子線程:pThread1->start();
如果線程已經(jīng)運(yùn)行,你重復(fù)調(diào)用start其實(shí)是不會進(jìn)行任何處理。

2、線程關(guān)閉

對于上面a類,在run中開啟的子線程,如果run中沒有調(diào)用exec(),使用quit(),exit(),是無法跳出run中的循環(huán),終止子線程的。不會發(fā)生任何效果,QThread不會因?yàn)槟阏{(diào)用quit()函數(shù)而退出正在運(yùn)行到一半的run。
但使用QThread的terminate()方法,可以立刻結(jié)束子線程,但這個(gè)函數(shù)存在非常不安定因素,不推薦使用。那么如何安全的終止一個(gè)線程呢?

最簡單的方法是添加一個(gè)bool變量,通過主線程修改這個(gè)bool變量來進(jìn)行終止,但這樣有可能引起訪問沖突,需要對其進(jìn)行加鎖。

void myThread::run()
{
    int count = 0;
    m_isCanRun = true;//標(biāo)記可以運(yùn)行
    QString str = QString("%1->%2,thread id:%3").arg(__FILE__).arg(__FUNCTION__)
    .arg((unsigned int)QThread::currentThreadId());
    emit message(str);
    while(1)
    {
        sleep(1);
        ++count;    
        doSomething();
        if(m_runCount == count)
        {
            break;
        }
        {
            QMutexLocker locker(&m_lock);// 此處加鎖,防止訪問沖突
            if(!m_isCanRun)//在每次循環(huán)判斷是否可以運(yùn)行,如果不行就退出循環(huán)
            {
                return;
            }
        }
    }
}

因此在子線程的run函數(shù)的循環(huán)中遇到m_isCanRun的判斷后就會退出run函數(shù),繼承QThread的函數(shù)在運(yùn)行完run函數(shù)后就視為線程完成,會發(fā)射finish信號。

子線程指針,盡量不要去delete ,這樣不安全。一般會綁定QObject::deleteLater()方法。

connect(pThread,&QThread::finished ,thread,&QObject::deleteLater);

線程結(jié)束后調(diào)用deleteLater來銷毀分配的內(nèi)存。

對于上面b類,在Qt4.8之后,Qt多線程的寫法最好還是通過QObject來實(shí)現(xiàn),和線程的交互通過信號和槽(實(shí)際上其實(shí)是通過事件)聯(lián)系。

繼承QObject多線程的方法線程的創(chuàng)建很簡單,只要讓QThread的start函數(shù)運(yùn)行起來就行,但是需要注意銷毀線程的方法: 在線程創(chuàng)建之后,這個(gè)QObject的銷毀不應(yīng)該在主線程里進(jìn)行,而是通過deleteLater槽進(jìn)行安全的銷毀,因此,繼承QObject多線程的方法在創(chuàng)建時(shí)有幾個(gè)槽函數(shù)需要特別關(guān)注:

  • 一個(gè)是QThread的finished信號對接QObject的deleteLater使得線程結(jié)束后,繼承QObject的那個(gè)多線程類會自己銷毀
  • 另一個(gè)是QThread的finished信號對接QThread自己的deleteLater,這個(gè)不是必須,下面官方例子就沒這樣做:
class Worker : public QObject
{
    Q_OBJECT
    public slots:
    void doWork(const QString &parameter) {
    QString result;
    /* ... here is the expensive or blocking operation ... */
    emit resultReady(result);
    }
signals:
    void resultReady(const QString &result);
};
class Controller : public QObject
{
    Q_OBJECT
    QThread workerThread;
public:
    Controller() {
    Worker *worker = new Worker;
    worker->moveToThread(&workerThread);
    connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
    connect(this, &Controller::operate, worker, &Worker::doWork);
    connect(worker, &Worker::resultReady, this, &Controller::handleResults);
    workerThread.start();
    }
    ~Controller() {
    workerThread.quit();
    workerThread.wait();
    }
public slots:
    void handleResults(const QString &);
signals:
    void operate(const QString &);
};

使用QObject創(chuàng)建多線程的方法如下:

  • 寫一個(gè)繼承QObject的類,對需要進(jìn)行復(fù)雜耗時(shí)邏輯的入口函數(shù)聲明為槽函數(shù)
  • 此類在舊線程new出來,不能給它設(shè)置任何父對象
  • 同時(shí)聲明一個(gè)QThread對象,在官方例子里,QThread并沒有new出來,這樣在析構(gòu)時(shí)就需要調(diào)用- – QThread::wait(),如果是堆分配的話, 可以通過deleteLater來讓線程自殺
  • 把obj通過moveToThread方法轉(zhuǎn)移到新線程中,此時(shí)object已經(jīng)是在線程中了
  • 把線程的finished信號和object的deleteLater槽連接,這個(gè)信號槽必須連接,否則會內(nèi)存泄漏
  • 正常連接其他信號和槽(在連接信號槽之前調(diào)用moveToThread,不需要處理connect的第五個(gè)參數(shù),否則就顯示聲明用Qt::QueuedConnection來連接)
  • 初始化完后調(diào)用’QThread::start()’來啟動線程
  • 在邏輯結(jié)束后,調(diào)用QThread::quit退出線程的事件循環(huán)

 到此這篇關(guān)于Qt線程QThread開啟和安全退出的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Qt QThread開啟和退出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++操作MySQL的實(shí)現(xiàn)示例

    C++操作MySQL的實(shí)現(xiàn)示例

    這篇文章主要介紹了C++操作MySQL的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • C語言超詳細(xì)講解指向函數(shù)的指針

    C語言超詳細(xì)講解指向函數(shù)的指針

    C語言程序在編譯后,每個(gè)函數(shù)都有一個(gè)首地址(也就是函數(shù)第一條指令的地址),這個(gè)地址稱為函數(shù)的指針??梢远x指向函數(shù)的指針變量,使用指針變量間接調(diào)用函數(shù)
    2022-07-07
  • C++中的const的使用詳解

    C++中的const的使用詳解

    這篇文章主要介紹了 C++中的const的使用詳解的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • 詳解C++編程中表達(dá)式的語義與計(jì)算順序

    詳解C++編程中表達(dá)式的語義與計(jì)算順序

    這篇文章主要介紹了C++編程中表達(dá)式的語義與計(jì)算順序,是C++入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2016-01-01
  • C語言讀取和存儲bmp格式圖片

    C語言讀取和存儲bmp格式圖片

    這篇文章主要為大家詳細(xì)介紹了C語言讀取和存儲bmp格式圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • C/C++實(shí)現(xiàn)監(jiān)控目錄文件變化

    C/C++實(shí)現(xiàn)監(jiān)控目錄文件變化

    ReadDirectoryChangesW是Windows操作系統(tǒng)提供的一個(gè)函數(shù),用于監(jiān)視目錄的變化,本文主要為大家介紹了如何使用ReadDirectoryChangesW實(shí)現(xiàn)監(jiān)控目錄文件變化,需要的可以參考下
    2023-11-11
  • C++深入講解哈夫曼樹

    C++深入講解哈夫曼樹

    給定N個(gè)權(quán)值作為N個(gè)葉子結(jié)點(diǎn),構(gòu)造一棵二叉樹,若該樹的帶權(quán)路徑長度達(dá)到最小,稱這樣的二叉樹為最優(yōu)二叉樹,也稱為哈夫曼樹(Huffman Tree)。哈夫曼樹是帶權(quán)路徑長度最短的樹,權(quán)值較大的結(jié)點(diǎn)離根較近
    2022-05-05
  • 使用C語言實(shí)現(xiàn)12種排序方法

    使用C語言實(shí)現(xiàn)12種排序方法

    這篇文章主要介紹了用C語言完整實(shí)現(xiàn)12種排序方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-12-12
  • C++ 微信多開的實(shí)現(xiàn)

    C++ 微信多開的實(shí)現(xiàn)

    本文主要介紹了C++ 微信多開的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 基于Matlab繪制超絢麗的煙花的過程詳解

    基于Matlab繪制超絢麗的煙花的過程詳解

    這篇文章主要為大家介紹了如何利用Matlab繪制超絢麗的煙花,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Matlab有一定幫助,需要的可以參考一下
    2022-02-02

最新評論