最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Qt基礎(chǔ)開發(fā)之Qt多線程類QThread與Qt定時器類QTimer的詳細(xì)方法與實例

 更新時間:2020年03月16日 08:51:46   作者:嚇人的猿  
這篇文章主要介紹了Qt基礎(chǔ)開發(fā)之Qt多線程類QThread與Qt定時器類QTimer的詳細(xì)方法與實例,需要的朋友可以參考下

Qt多線程

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

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 <QApplication>
#include <QThread>
#include <QDebug>
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 <QThread>
#include <QDebug>
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 <QApplication>
#include <QThread>
#include <QDebug>
#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í)行完進(jìn)入線程exec()中,可以通過發(fā)射信號重新讓槽函數(shù)在線程中執(zhí)行。也可以通過quit()退出線程exec()。
  2. QObject派生類對象,將要調(diào)用moveToThread,不能指定一個主線程父對象托管內(nèi)存。
  3. QWidget的對象及派生類對象都只能在GUI主線程運(yùn)行,不能使用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 <QThread>
#include <QDebug>
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 <QWidget>
#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 <QPushButton>
#include "mywork.h"
#include <QThread>
#include <QHBoxLayout>
​
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)蛋糕,這個在多線程中叫作同步方法。

​需要注意的是,同步不是同時,而是有序進(jìn)行。

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、信號量

​互斥鎖保護(hù)的資源同一時刻只能有一個線程能夠獲取使用權(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 <QTimer>
#include <qdebug.h>
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的詳細(xì)方法與實例,更多關(guān)于Qt開發(fā)知識請查看下面的相關(guān)鏈接

相關(guān)文章

  • C++11?中的override詳解

    C++11?中的override詳解

    這篇文章主要介紹了C++11?中的override詳解,本文以重寫虛函數(shù)時,容易犯的四個錯誤為例,結(jié)合示例代碼給大家詳細(xì)介紹,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • C#復(fù)制和深度復(fù)制的實現(xiàn)方法

    C#復(fù)制和深度復(fù)制的實現(xiàn)方法

    下面小編就為大家?guī)硪黄狢#復(fù)制和深度復(fù)制的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • C++哈希表之閉散列方法的模擬實現(xiàn)詳解

    C++哈希表之閉散列方法的模擬實現(xiàn)詳解

    閉散列指(開放定址法)發(fā)生沖突時,如果哈希表沒有被填滿,則表內(nèi)一定還有其他空閑位置,可以把沖突值放到下一個沒有被占用的空余位置上。本文將模擬實現(xiàn)閉散列方法,需要的可以參考一下
    2022-11-11
  • 原創(chuàng)的C語言控制臺小游戲

    原創(chuàng)的C語言控制臺小游戲

    本文給大家分享的是個人原創(chuàng)設(shè)計的一個C語言控制臺小游戲,非常的簡單,但是挺好玩的,推薦給大家,有需要的小伙伴也可以自由擴(kuò)展下。
    2015-03-03
  • C++中實現(xiàn)把表的數(shù)據(jù)導(dǎo)出到EXCEL并打印實例代碼

    C++中實現(xiàn)把表的數(shù)據(jù)導(dǎo)出到EXCEL并打印實例代碼

    這篇文章主要介紹了實現(xiàn)把表的數(shù)據(jù)導(dǎo)出到EXCEL并打印實例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • Qt?Qml實現(xiàn)任意角為圓角的矩形

    Qt?Qml實現(xiàn)任意角為圓角的矩形

    在?Qml?中,矩形(Rectangle)是最常用的元素之一,本文將介紹如何通過自定義?Qml?元素實現(xiàn)一個任意角可為圓角的矩形,感興趣的可以了解下
    2025-01-01
  • C++中std::invalid_argument報錯解決

    C++中std::invalid_argument報錯解決

    在C++編程中,std::invalid_argument是一個常見的異常,用于指示函數(shù)參數(shù)無效,文章詳細(xì)解析了這一異常的產(chǎn)生原因,并提供了多種解決策略,感興趣的可以了解一下
    2024-09-09
  • C語言實現(xiàn)簡單掃雷源碼

    C語言實現(xiàn)簡單掃雷源碼

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)簡單掃雷源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內(nèi)存中的數(shù)據(jù)都是暫時的,當(dāng)程序結(jié)束時,它們都將丟失,為了永久性的保存大量的數(shù)據(jù),C語言提供了對文件的操作,這篇文章主要給大家介紹了關(guān)于C語言中文件操作的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • C/C++細(xì)數(shù)宏與函數(shù)有那些區(qū)別

    C/C++細(xì)數(shù)宏與函數(shù)有那些區(qū)別

    在C程序中,可以用宏代碼提高執(zhí)行效率。宏代碼本身不是函數(shù),但使用起來象函數(shù)。預(yù)處理器用復(fù)制宏代碼的方式代替函數(shù)調(diào)用,省去了參數(shù)壓棧、生成匯編語言的CALL調(diào)用、返回參數(shù)、執(zhí)行return等過程,從而提高了速度
    2022-10-10

最新評論

开封县| 三穗县| 南雄市| 舞阳县| 八宿县| 泽库县| 西藏| 永嘉县| 包头市| 奈曼旗| 红桥区| 康马县| 日喀则市| 琼结县| 新丰县| 贵溪市| 辛集市| 德钦县| 洛阳市| 宜兰县| 锦屏县| 临桂县| 于都县| 博湖县| 红河县| 武夷山市| 石城县| 五家渠市| 长沙县| 卢龙县| 高青县| 克拉玛依市| 洛浦县| 卢湾区| 孝感市| 历史| 嘉鱼县| 锡林浩特市| 塘沽区| 五河县| 丹江口市|