C/C++ Qt QThread線程組件的具體使用
QThread庫是QT中提供的跨平臺(tái)多線程實(shí)現(xiàn)方案,使用時(shí)需要繼承QThread這個(gè)基類,并重寫實(shí)現(xiàn)內(nèi)部的Run方法,由于該庫是基本庫,默認(rèn)依賴于QtCore.dll這個(gè)基礎(chǔ)模塊,在使用時(shí)無需引入其他模塊.
實(shí)現(xiàn)簡(jiǎn)單多線程
QThread庫提供了跨平臺(tái)的多線程管理方案,通常一個(gè)QThread對(duì)象管理一個(gè)線程,在使用是需要從QThread類繼承并重寫內(nèi)部的Run方法,并在Run方法內(nèi)部實(shí)現(xiàn)多線程代碼.
#include <QCoreApplication>
#include <iostream>
#include <QThread>
class MyThread: public QThread
{
protected:
volatile bool m_to_stop;
protected:
// 線程函數(shù)必須使用Run作為開始
void run()
{
for(int x=0; !m_to_stop && (x <10); x++)
{
msleep(1000);
std::cout << objectName().toStdString() << std::endl;
}
}
public:
MyThread()
{
m_to_stop = false;
}
// 用于設(shè)置結(jié)束符號(hào)為真
void stop()
{
m_to_stop = true;
}
// 輸出線程運(yùn)行狀態(tài)
void is_run()
{
std::cout << "Thread Running = " << isRunning() << std::endl;
}
// 輸出線程完成狀態(tài)(是否結(jié)束)
void is_finish()
{
std::cout << "Thread Finished = " << isFinished() << std::endl;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 定義線程數(shù)組
MyThread thread[10];
// 設(shè)置線程對(duì)象名字
for(int x=0;x<10;x++)
{
thread[x].setObjectName(QString("thread => %1").arg(x));
}
// 批量調(diào)用run執(zhí)行
for(int x=0;x<10;x++)
{
thread[x].start();
thread[x].is_run();
thread[x].isFinished();
}
// 批量調(diào)用stop關(guān)閉
for(int x=0;x<10;x++)
{
thread[x].wait();
thread[x].stop();
thread[x].is_run();
thread[x].is_finish();
}
return a.exec();
}
向線程中傳遞參數(shù)
線程在執(zhí)行前可以通過調(diào)用MyThread中的自定義函數(shù),并在函數(shù)內(nèi)實(shí)現(xiàn)參數(shù)賦值,實(shí)現(xiàn)線程傳參操作.
#include <QCoreApplication>
#include <iostream>
#include <QThread>
class MyThread: public QThread
{
protected:
int m_begin;
int m_end;
int m_result;
void run()
{
m_result = m_begin + m_end;
}
public:
MyThread()
{
m_begin = 0;
m_end = 0;
m_result = 0;
}
// 設(shè)置參數(shù)給當(dāng)前線程
void set_value(int x,int y)
{
m_begin = x;
m_end = y;
}
// 獲取當(dāng)前線程名
void get_object_name()
{
std::cout << "this thread name => " << objectName().toStdString() << std::endl;
}
// 獲取線程返回結(jié)果
int result()
{
return m_result;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyThread thread[3];
// 分別將不同的參數(shù)傳入到線程函數(shù)內(nèi)
for(int x=0; x<3; x++)
{
thread[x].set_value(1,2);
thread[x].setObjectName(QString("thread -> %1").arg(x));
thread[x].start();
}
// 等待所有線程執(zhí)行結(jié)束
for(int x=0; x<3; x++)
{
thread[x].get_object_name();
thread[x].wait();
}
// 獲取線程返回值并相加
int result = thread[0].result() + thread[1].result() + thread[2].result();
std::cout << "sum => " << result << std::endl;
return a.exec();
}
QMutex 互斥同步線程鎖
QMutex類是基于互斥量的線程同步鎖,該鎖lock()鎖定與unlock()解鎖必須配對(duì)使用,線程鎖保證線程間的互斥,利用線程鎖能夠保證臨界資源的安全性.
- 線程鎖解決的問題: 多個(gè)線程同時(shí)操作同一個(gè)全局變量,為了防止資源的無序覆蓋現(xiàn)象,從而需要增加鎖,來實(shí)現(xiàn)多線程搶占資源時(shí)可以有序執(zhí)行.
- 臨界資源(Critical Resource): 每次只允許一個(gè)線程進(jìn)行訪問 (讀/寫)的資源.
- 線程間的互斥(競(jìng)爭(zhēng)): 多個(gè)線程在同一時(shí)刻都需要訪問臨界資源.
- 一般性原則: 每一個(gè)臨界資源都需要一個(gè)線程鎖進(jìn)行保護(hù).
#include <QCoreApplication>
#include <iostream>
#include <QThread>
#include <QMutex>
static QMutex g_mutex; // 線程鎖
static QString g_store; // 定義全局變量
class Producer : public QThread
{
protected:
void run()
{
int count = 0;
while(true)
{
// 加鎖
g_mutex.lock();
g_store.append(QString::number((count++) % 10));
std::cout << "Producer -> "<< g_store.toStdString() << std::endl;
// 釋放鎖
g_mutex.unlock();
msleep(900);
}
}
};
class Customer : public QThread
{
protected:
void run()
{
while( true )
{
g_mutex.lock();
if( g_store != "" )
{
g_store.remove(0, 1);
std::cout << "Curstomer -> "<< g_store.toStdString() << std::endl;
}
g_mutex.unlock();
msleep(1000);
}
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Producer p;
Customer c;
p.setObjectName("producer");
c.setObjectName("curstomer");
p.start();
c.start();
return a.exec();
}
QMutexLocker是在QMutex基礎(chǔ)上簡(jiǎn)化版的線程鎖,QMutexLocker會(huì)保護(hù)加鎖區(qū)域,并自動(dòng)實(shí)現(xiàn)互斥量的鎖定和解鎖操作,可以將其理解為是智能版的QMutex鎖,該鎖只需要在上方代碼中稍加修改即可.
#include <QMutex>
#include <QMutexLocker>
static QMutex g_mutex; // 線程鎖
static QString g_store; // 定義全局變量
class Producer : public QThread
{
protected:
void run()
{
int count = 0;
while(true)
{
// 增加智能線程鎖
QMutexLocker Locker(&g_mutex);
g_store.append(QString::number((count++) % 10));
std::cout << "Producer -> "<< g_store.toStdString() << std::endl;
msleep(900);
}
}
};
互斥鎖存在一個(gè)問題,每次只能有一個(gè)線程獲得互斥量的權(quán)限,如果在程序中有多個(gè)線程來同時(shí)讀取某個(gè)變量,那么使用互斥量必須排隊(duì),效率上會(huì)大打折扣,基于QReadWriteLock讀寫模式進(jìn)行代碼段鎖定,即可解決互斥鎖存在的問題.
QReadWriteLock 讀寫同步線程鎖
該鎖允許用戶以同步讀lockForRead()或同步寫lockForWrite()兩種方式實(shí)現(xiàn)保護(hù)資源,但只要有一個(gè)線程在以寫的方式操作資源,其他線程也會(huì)等待寫入操作結(jié)束后才可繼續(xù)讀資源.
#include <QCoreApplication>
#include <iostream>
#include <QThread>
#include <QMutex>
#include <QReadWriteLock>
static QReadWriteLock g_mutex; // 線程鎖
static QString g_store; // 定義全局變量
class Producer : public QThread
{
protected:
void run()
{
int count = 0;
while(true)
{
// 以寫入方式鎖定資源
g_mutex.lockForWrite();
g_store.append(QString::number((count++) % 10));
// 寫入后解鎖資源
g_mutex.unlock();
msleep(900);
}
}
};
class Customer : public QThread
{
protected:
void run()
{
while( true )
{
// 以讀取方式寫入資源
g_mutex.lockForRead();
if( g_store != "" )
{
std::cout << "Curstomer -> "<< g_store.toStdString() << std::endl;
}
// 讀取到后解鎖資源
g_mutex.unlock();
msleep(1000);
}
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Producer p1,p2;
Customer c1,c2;
p1.setObjectName("producer 1");
p2.setObjectName("producer 2");
c1.setObjectName("curstomer 1");
c2.setObjectName("curstomer 2");
p1.start();
p2.start();
c1.start();
c2.start();
return a.exec();
}
QSemaphore 基于信號(hào)線程鎖
信號(hào)量是特殊的線程鎖,信號(hào)量允許N個(gè)線程同時(shí)訪問臨界資源,通過acquire()獲取到指定資源,release()釋放指定資源.
#include <QCoreApplication>
#include <iostream>
#include <QThread>
#include <QSemaphore>
const int SIZE = 5;
unsigned char g_buff[SIZE] = {0};
QSemaphore g_sem_free(SIZE); // 5個(gè)可生產(chǎn)資源
QSemaphore g_sem_used(0); // 0個(gè)可消費(fèi)資源
// 生產(chǎn)者生產(chǎn)產(chǎn)品
class Producer : public QThread
{
protected:
void run()
{
while( true )
{
int value = qrand() % 256;
// 若無法獲得可生產(chǎn)資源,阻塞在這里
g_sem_free.acquire();
for(int i=0; i<SIZE; i++)
{
if( !g_buff[i] )
{
g_buff[i] = value;
std::cout << objectName().toStdString() << " --> " << value << std::endl;
break;
}
}
// 可消費(fèi)資源數(shù)+1
g_sem_used.release();
sleep(2);
}
}
};
// 消費(fèi)者消費(fèi)產(chǎn)品
class Customer : public QThread
{
protected:
void run()
{
while( true )
{
// 若無法獲得可消費(fèi)資源,阻塞在這里
g_sem_used.acquire();
for(int i=0; i<SIZE; i++)
{
if( g_buff[i] )
{
int value = g_buff[i];
g_buff[i] = 0;
std::cout << objectName().toStdString() << " --> " << value << std::endl;
break;
}
}
// 可生產(chǎn)資源數(shù)+1
g_sem_free.release();
sleep(1);
}
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Producer p1;
Customer c1;
p1.setObjectName("producer");
c1.setObjectName("curstomer");
p1.start();
c1.start();
return a.exec();
}
到此這篇關(guān)于C/C++ Qt QThread線程組件的具體使用的文章就介紹到這了,更多相關(guān)Qt QThread線程使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)自定義撤銷重做功能的示例代碼
在使用c++做界面開發(fā)的時(shí)候,尤其是實(shí)現(xiàn)白板功能時(shí)需要自己實(shí)現(xiàn)一套撤銷重做功能.如果是qt則有QUndoable對(duì)象,可以直接拿來用。但是如果是使用gdi繪圖,則可能需要自己實(shí)現(xiàn)了。本文就來用C++實(shí)現(xiàn)自定義撤銷重做功能,需要的可以參考一下2022-12-12
C語言SetConsoleCursorPosition函數(shù)使用方法
這篇文章介紹了C語言SetConsoleCursorPosition函數(shù)的使用方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12
C語言用棧模擬實(shí)現(xiàn)隊(duì)列問題詳解
本片文章帶你分析如何用兩個(gè)棧,并且只使用棧的基本功能來模擬實(shí)現(xiàn)隊(duì)列,其中同樣只實(shí)現(xiàn)隊(duì)列的基本功能,感興趣的朋友來看看吧2022-04-04

