亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

Qt多線程

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

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

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

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

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

首先要繼承QThread

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

[virtual protected] void QThread::run()
 /*
 * 基類(lèi)QThread的run函數(shù)只是簡(jiǎn)單啟動(dòng)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),有時(shí)候不是馬上退出,需要等到cpu的控制權(quán)交還給線程的exec()。

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

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

繼承 QObject

實(shí)例化一個(gè)QThread對(duì)象

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

QObject子類(lèi)對(duì)象通過(guò)moveToThread將自己放到線程QThread對(duì)象中.

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

必須通過(guò)發(fā)射信號(hào)來(lái)讓槽函數(shù)在線程中執(zhí)行,發(fā)射的信號(hào)存放在線程exec()消息隊(duì)列中。

例如:

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來(lái)回收線程資源
 qDebug() << "thread is runing" << thread.isRunning() << endl;
​
 return app.exec();
}

需要特別注意的是:

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

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

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

先把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ā)射信號(hào)給在另外一個(gè)線程的對(duì)象的隊(duì)列中*/
 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線程的同步

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

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

3.1、互斥鎖

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

​例如:

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

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

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

有時(shí)候我們會(huì)忘記釋放鎖,Qt還為我們提供了管理鎖的類(lèi)QMutexLocker

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

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

3.2、信號(hào)量

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

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

4、Qt定時(shí)器QTimer

​定時(shí)器可以隔一段時(shí)間發(fā)出信號(hào),通過(guò)接收這個(gè)信號(hào)來(lái)處理一些定時(shí)任務(wù),需要注意的是,定時(shí)器并沒(méi)有開(kāi)啟一個(gè)新線程。Qt中的定時(shí)器是QTimer繼承自QObject。

通過(guò)QTimer::start()來(lái)啟動(dòng)定時(shí)器

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

通過(guò)鏈接信號(hào)timeout()來(lái)處理一些定時(shí)任務(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多線程類(lèi)QThread與Qt定時(shí)器類(lèi)QTimer的詳細(xì)方法與實(shí)例,更多關(guān)于Qt開(kāi)發(fā)知識(shí)請(qǐng)查看下面的相關(guān)鏈接

  • 詳解C++實(shí)現(xiàn)匈牙利算法

    詳解C++實(shí)現(xiàn)匈牙利算法

    匈牙利算法是一種在多項(xiàng)式時(shí)間內(nèi)求解任務(wù)分配問(wèn)題的組合優(yōu)化算法,并推動(dòng)了后來(lái)的原始對(duì)偶方法。美國(guó)數(shù)學(xué)家哈羅德·庫(kù)恩于1955年提出該算法。此算法之所以被稱(chēng)作匈牙利算法,是因?yàn)樗惴ê艽笠徊糠质腔谝郧靶傺览麛?shù)學(xué)家Dénes K&#337;nig和Jen&#337; Egerváry的工作之上創(chuàng)建起來(lái)的
    2021-06-06
  • 詳解C++17中類(lèi)模板參數(shù)推導(dǎo)的使用

    詳解C++17中類(lèi)模板參數(shù)推導(dǎo)的使用

    自C++17起就通過(guò)使用類(lèi)模板參數(shù)推導(dǎo),只要編譯器能根據(jù)初始值推導(dǎo)出所有模板參數(shù),那么就可以不指明參數(shù),下面我們就來(lái)看看C++17中類(lèi)模板參數(shù)推導(dǎo)的具體使用吧
    2024-03-03
  • C語(yǔ)言實(shí)現(xiàn)單詞小助手功能完善版

    C語(yǔ)言實(shí)現(xiàn)單詞小助手功能完善版

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)單詞小助手功能的完善版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • C語(yǔ)言各種符號(hào)的使用介紹上篇

    C語(yǔ)言各種符號(hào)的使用介紹上篇

    C 語(yǔ)言的基本符號(hào)就有 20 多個(gè),每個(gè)符號(hào)可能同時(shí)具有多重含義,而且這些符號(hào)之間相互組合又使得 C 語(yǔ)言中的符號(hào)變得更加復(fù)雜起來(lái)
    2022-08-08
  • C語(yǔ)言由淺入深講解文件的操作下篇

    C語(yǔ)言由淺入深講解文件的操作下篇

    C語(yǔ)言具有操作文件的能力,比如打開(kāi)文件、讀取和追加數(shù)據(jù)、插入和刪除數(shù)據(jù)、關(guān)閉文件、刪除文件等。與其他編程語(yǔ)言相比,C語(yǔ)言文件操作的接口相當(dāng)簡(jiǎn)單和易學(xué)
    2022-04-04
  • 七夕表白! C語(yǔ)言實(shí)現(xiàn)愛(ài)情紅玫瑰

    七夕表白! C語(yǔ)言實(shí)現(xiàn)愛(ài)情紅玫瑰

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)愛(ài)情紅玫瑰,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • C++ odr用法案例詳解

    C++ odr用法案例詳解

    這篇文章主要介紹了C++ odr用法案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • C語(yǔ)言面試C++字符串替換空格示例

    C語(yǔ)言面試C++字符串替換空格示例

    這篇文章主要介紹了C語(yǔ)言面試中C++字符串替換空格示例,文中給出了基本上可以拿下offer的代碼,有需要的朋友可以借鑒參考下,希望大家都能早日拿到心儀的offer
    2021-09-09
  • C++?雙向循環(huán)鏈表類(lèi)模版實(shí)例詳解

    C++?雙向循環(huán)鏈表類(lèi)模版實(shí)例詳解

    這篇文章主要為大家詳細(xì)介紹了C++?雙向循環(huán)鏈表類(lèi)模版實(shí)例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-02-02
  • 最新評(píng)論