1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      Qt基礎(chǔ)開發(fā)之Qt多線程類QThread與Qt定時器類QTimer的詳細方法與實例

      Qt多線程

      我們之前的程序都是單線程運行,接下來我們開始引入多線程。就相當于以前的一個人在工作,現(xiàn)在多個人一起工作。

      “專業(yè)、務(wù)實、高效、創(chuàng)新、把客戶的事當成自己的事”是我們每一個人一直以來堅持追求的企業(yè)文化。 創(chuàng)新互聯(lián)是您可以信賴的網(wǎng)站建設(shè)服務(wù)商、專業(yè)的互聯(lián)網(wǎng)服務(wù)提供商! 專注于網(wǎng)站建設(shè)、網(wǎng)站設(shè)計、軟件開發(fā)、設(shè)計服務(wù)業(yè)務(wù)。我們始終堅持以客戶需求為導(dǎo)向,結(jié)合用戶體驗與視覺傳達,提供有針對性的項目解決方案,提供專業(yè)性的建議,創(chuàng)新互聯(lián)建站將不斷地超越自我,追逐市場,引領(lǐng)市場!

      Qt中非常有必要使用多線程,這是因為,Qt應(yīng)用是事件驅(qū)動型的,一旦某個事件處理函數(shù)處理時間過久,就會造成其它的事件得不到及時處理。

      Qt中使用QThread來管理線程,一個QThread對象,就是一個線程。QThread對象也有消息循序exec()函數(shù),用來處理自己這個線程的事件。

      Qt實現(xiàn)多線程有兩種方式

      ​1、Qt第一種創(chuàng)建線程方式

      首先要繼承QThread

      重寫虛函數(shù)QThread::run

      [virtual protected] void QThread::run()
       /*
       * 基類QThread的run函數(shù)只是簡單啟動exec()消息循環(huán)
       */

      例如:

      #include 
      #include 
      #include 
      class MyThread : public QThread
      {
      public:
       void run()
       {
        qDebug() << "QThread begin" << endl;
        qDebug() << "child thread" << QThread::currentThreadId() << endl;
        QThread::sleep(5);
        qDebug() << "QThread end" << endl;
        exec();
       }
      };
      ​
      int main(int argc, char** argv)
      {
       QApplication app(argc, argv);
      ​
       MyThread thread;
       thread.start();
       qDebug() << "main thread" << QThread::currentThreadId() << endl;
       QThread::sleep(5);
       qDebug() << "main thread" << QThread::currentThreadId() << endl;
       thread.quit();
       qDebug() << "main thread thread.quit()" << endl;
       tread.wait();
       qDebug() << "main thread thread.wait()" << endl;
       return app.exec();
      }

      使用QThread的quit可以退出線程的消息循環(huán),有時候不是馬上退出,需要等到cpu的控制權(quán)交還給線程的exec()。

      一般在子線程退出的時候需要主線程去回收資源,可以調(diào)用QThread的wait,等待子線程的退出,然后回收資源.

      2、Qt第二種創(chuàng)建線程方式

      繼承 QObject

      實例化一個QThread對象

      實現(xiàn)槽函數(shù).

      QObject子類對象通過moveToThread將自己放到線程QThread對象中.

      調(diào)用QThread對象的start函數(shù)啟動線程

      必須通過發(fā)射信號來讓槽函數(shù)在線程中執(zhí)行,發(fā)射的信號存放在線程exec()消息隊列中。

      例如:

      mywork.h

      #ifndef MYWORK_H
      #define MYWORK_H
      #include 
      #include 
      class MyWork : public QObject
      {
       Q_OBJECT
      public slots:
       void workSlot()
       {
        qDebug() << "QThread begin" << endl;
        qDebug() << "child thread" << QThread::currentThreadId() << endl;
        QThread::sleep(5);
        qDebug() << "QThread end" << endl;
       }
      };
      #endif // MYWORK_H

      widget.cpp

      #include 
      #include 
      #include 
      #include "mywork.h"
      ​
      int main(int argc, char** argv)
      {
       qDebug() << "main thread" << QThread::currentThreadId() << endl;
       QApplication app(argc, argv);
       QThread thread;
       MyWork work;
       work.moveToThread(&thread);
       QObject::connect(&thread, SIGNAL(started()), &work, SLOT(workSlot()));
       thread.start();
       
       QThread::sleep(6);
       qDebug() << "thread is runing" << thread.isRunning() << endl;
       thread.quit(); //調(diào)用quit讓線程退出消息循環(huán),否則線程一直在exec循環(huán)中
       thread.wait(); //調(diào)用完quit后緊接著要調(diào)用wait來回收線程資源
       qDebug() << "thread is runing" << thread.isRunning() << endl;
      ​
       return app.exec();
      }

      需要特別注意的是:

      1. 線槽函數(shù)已經(jīng)執(zhí)行完進入線程exec()中,可以通過發(fā)射信號重新讓槽函數(shù)在線程中執(zhí)行。也可以通過quit()退出線程exec()。
      2. QObject派生類對象,將要調(diào)用moveToThread,不能指定一個主線程父對象托管內(nèi)存。
      3. QWidget的對象及派生類對象都只能在GUI主線程運行,不能使用moveToThread移到子線程中,即使沒有指定父對象。

      多線程對象內(nèi)存釋放

      既然QObject對象無法托管內(nèi)存對象,那么到底是先釋放線程對象,還是先釋放這個QObject對象?

      先把QObject在線程循環(huán)中釋放(使用QObject::deleteLater函數(shù)),然后QThread::quit,然后QThread::wait。

      例如:

      ​mywork.h

      #ifndef MYWORK_H
      #define MYWORK_H
      ​
      #include 
      #include 
      class MyWork : public QObject
      {
       Q_OBJECT
      public:
      ​
       ~MyWork() { qDebug() << __FUNCTION__ << endl; }
      public slots:
       void workSlot()
       {
        while(1)
        {
         qDebug() << "Work begin" << endl;
         QThread::sleep(5);
         qDebug() << "work end" << endl;
        }
       }
       void otherWorkSlot()
       {
        qDebug() << "otherWork begin" << endl;
        QThread::sleep(5);
        qDebug() << "otherWork end" << endl;
       }
      ​
      ​
      };
      ​
      #endif // MYWORK_H

      widget.h

      #ifndef WIDGET_H
      #define WIDGET_H
      ​
      #include 
      #include "mywork.h"
      ​
      class Widget : public QWidget
      {
       Q_OBJECT
      ​
      public:
       Widget(QWidget *parent = 0);
       ~Widget();
      private:
       QThread *_thread;
       MyWork * _myWork;
      };
      ​
      #endif // WIDGET_H

      widget.cpp

      #include "widget.h"
      #include 
      #include "mywork.h"
      #include 
      #include 
      ​
      Widget::Widget(QWidget *parent)
       : QWidget(parent)
      {
       _myWork = new MyWork;
       _thread = new QThread(this);
       _myWork->moveToThread(_thread);
       _thread->start();
      ​
       QPushButton *pb0 = new QPushButton("work", this);
       QPushButton *pb1 = new QPushButton("pb", this);
       QHBoxLayout *hBox = new QHBoxLayout(this);
       hBox->addWidget(pb0);
       hBox->addWidget(pb1);
       this->setLayout(hBox);
      ​
       /*發(fā)射信號給在另外一個線程的對象的隊列中*/
       connect(pb0, SIGNAL(clicked()), _myWork, SLOT(workSlot()));
       connect(pb1, SIGNAL(clicked()), _myWork, SLOT(otherWorkSlot()));
      ​
       /*推薦用法釋放內(nèi)存*/
       //connect(_thread, SIGNAL(finished()), _myWork, SLOT(deleteLater()));
      ​
      }
      ​
      Widget::~Widget()
      {
       _myWork->deleteLater(); //一定要在QThread線程退出之前
       _thread->quit();
       _thread->wait();
      }

      3、Qt線程的同步

      ​多線程在訪問同時一個資源,(例如:多個線程可操作的變量、函數(shù)等),到底誰來使用這個資源是一個問題,就像一大群人去搶同一塊蛋糕,可能其中一個人搶到,更有可能蛋糕被搶個稀爛。在多線程中,這個叫作競爭冒險。那么我們需要定一個規(guī)則來約束每一個人,比如:每個人排隊來領(lǐng)蛋糕,這個在多線程中叫作同步方法。

      ​需要注意的是,同步不是同時,而是有序進行。

      3.1、互斥鎖

      ​Qt中的互斥鎖是QMutex,不繼承任何Qt基類,使用QMutex來鎖共享資源,哪個線程搶到鑰匙,哪個線程就有這個資源的使用權(quán),其它線程等待這個線程使用完資源并歸還鑰匙,然后它們再去搶鑰匙。

      ​例如:

      QMutex mutex; //這對象一般定義在多個線程能訪問的地方
      mutex.lock(); //多個線程調(diào)用這個函數(shù)去獲取鎖,沒有獲取到的線程,將阻塞等待在這個函數(shù)上。
      mutex.unlock(); //釋放鎖

      QMutex::lock函數(shù)會讓線程等待獲取鎖,如果不想等待,可以使用一下函數(shù)替換:

      bool QMutex::tryLock(int timeout = 0)
      /*
      *參數(shù) int timeout:等到timeout毫秒,不管有沒獲取到鎖都返回,timeout為0時,直接返回。
      *返回值 true代表獲取到鎖,false沒有獲取到
      */

      有時候我們會忘記釋放鎖,Qt還為我們提供了管理鎖的類QMutexLocker

      QMutex mutex;
      void func()
      {
       QMutexLocker locker(_mutex); //QMutexLocker最好實例化成棧對象,釋放之前將QMutex解鎖。 
      }

      以上例子,一旦func()執(zhí)行完成locker自動釋放,釋放之前先解鎖。

      3.2、信號量

      ​互斥鎖保護的資源同一時刻只能有一個線程能夠獲取使用權(quán),有些資源是可以限定多個線程同時訪問,那么這個時候可以使用信號量。在Qt中信號量為QSemaphore。

      QSemaphore sem(2) //初始化信號量為2
      sem.acquire(); //信號量部位0的時候,調(diào)用這個函數(shù)會讓信號量-1,一旦信號量為零,阻塞等待
      semaphore.release(); //使信號量+1

      4、Qt定時器QTimer

      ​定時器可以隔一段時間發(fā)出信號,通過接收這個信號來處理一些定時任務(wù),需要注意的是,定時器并沒有開啟一個新線程。Qt中的定時器是QTimer繼承自QObject。

      通過QTimer::start()來啟動定時器

      void start(int msec)
      /*
      *定時msec毫秒后,發(fā)射timeout()信號
      */

      通過鏈接信號timeout()來處理一些定時任務(wù),例如:

      #include "dialog.h"
      #include 
      #include 
      Dialog::Dialog(QWidget *parent)
       : QDialog(parent)
      {
       QTimer *timer = new QTimer(this);
       connect(timer, SIGNAL(timeout()), this, SLOT(doSomeThing()));
       timer->start(3000);
       
      }
      void Dialog::doSomeThing()
      {
       qDebug() << __FUNCTION__ << endl;
      }
      ​
      Dialog::~Dialog()
      {
      ​
      }

      本文主要介紹了Qt多線程類QThread與Qt定時器類QTimer的詳細方法與實例,更多關(guān)于Qt開發(fā)知識請查看下面的相關(guān)鏈接


      分享題目:Qt基礎(chǔ)開發(fā)之Qt多線程類QThread與Qt定時器類QTimer的詳細方法與實例
      當前鏈接:http://ef60e0e.cn/article/pdgpjp.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        安泽县| 和田市| 明溪县| 福建省| 怀远县| 望谟县| 浪卡子县| 横山县| 虞城县| 汾西县| 交口县| 时尚| 乌拉特中旗| 清流县| 庆元县| 汕尾市| 英超| 上饶市| 抚顺县| 内乡县| 将乐县| 南漳县| 安龙县| 澎湖县| 扬中市| 都江堰市| 清远市| 五大连池市| 临泉县| 柘荣县| 大宁县| 色达县| 锡林浩特市| 叙永县| 疏附县| 古浪县| 文安县| 长沙市| 广水市| 综艺| 鄄城县|