柚子快報邀請碼778899分享:開發(fā)語言 QT--線程
柚子快報邀請碼778899分享:開發(fā)語言 QT--線程
一、線程QThread
QThread 類提供不依賴平臺的管理線程的方法,如果要設計多線程程序,一般是從 QThread繼承定義一個線程類,在自定義線程類里進行任務處理。qt擁有一個GUI線程,該線程阻塞式監(jiān)控窗體,來自任何用戶的操作都會被gui捕獲到,并處理;如果有耗時的任務,不推薦在GUI中處理.怎么辦?? 創(chuàng)建線程,交給線程去耗時!
1.QThread類簡要說明
一個QThread類的對象管理一個線程。該線程包括
執(zhí)行函數(shù)體,這是線程執(zhí)行的主要代碼部分。函數(shù)體中有一個死循環(huán),用于保持線程的持續(xù)運行,直到條件滿足。線程私有空間,每個線程都有自己的獨立數(shù)據(jù)和堆??臻g。
QThread 提供了完整的線程功能,并且內(nèi)置了一個虛函數(shù) run() 用于處理線程任務。我們可以通過重寫 run() 方法來定義線程的具體行為。編寫線程的具體方法為繼承QThread并重寫run()函數(shù)。最好是直接定義一個線程類(實際上也這樣做)。GUI線程和控件訪問:只有主GUI線程可以訪問和操作窗體上的控件。如果其他線程嘗試直接訪問這些控件,會導致程序崩潰。為了在線程中更新UI,可以使用信號和槽機制。
class MyThread : public QThread {
Q_OBJECT
signals:
void updateUI(int value);
public:
void run() override {
for (int i = 0; i < 10; ++i) {
emit updateUI(i); // 發(fā)出信號更新UI
QThread::sleep(1);
}
}
};
// 在主窗口類中連接信號和槽
connect(ptMyThread, &MyThread::updateUI, this, &MainWindow::updateUIFunction);
線程的啟動和停止使用start()和stop()函數(shù)即可。這也是可以捕獲的信號,可以用來連接槽函數(shù),不過要加上ed。出現(xiàn)了此類錯誤error: undefined reference to `vtable for myThread,那么就將該錯誤發(fā)生的頭文件和函數(shù)體文件移除該工程,然后再添加進來。代碼舉例
2.線程間通信
1.通過共享資源的方式可以進行線程間通信。
結(jié)構(gòu)體通信
值得注意的就是使用之前要加鎖,使用之后要解鎖
QMutex buflock;//其實就是互斥信號量。
buflock.lock();
buflock.unlock();
結(jié)構(gòu)體要在使用該結(jié)構(gòu)體的線程中聲明,定義在外面,方便其他線程使用或聲明,當然互斥鎖也要有哈。
一般通過構(gòu)造函數(shù)傳入或?qū)懗鰯?shù)據(jù)。
在重寫run()函數(shù)里有while循環(huán),或者是死循環(huán),具體情況而定
當然也要有休眠函數(shù),給其他線程一點時間執(zhí)行嘛。
代碼舉例
//rethread.h
#ifndef RETHREAD_H
#define RETHREAD_H
#include
#include
struct msg_struct{
int temp;
int shidu;
char des[128];
};
class thread_write:public QThread{
public:
thread_write();
thread_write(struct msg_struct *pmsg,QMutex *pMutex);//寫
~thread_write();
void run() override;//寫。重寫
private:
struct msg_struct *pShareMsg;
QMutex *pMutex;
};
class thread_read:public QThread{
public:
thread_read(struct msg_struct *pmsg,QMutex *pMutex);//寫
thread_read();
~thread_read();
void run() override;//重寫
private:
struct msg_struct *pShareMsg;
QMutex *pMutex;
};
#endif // RETHREAD_H
//rethread.cpp
#include "rethread.h"
#include
thread_write::thread_write()
{
}
thread_write::thread_write(msg_struct *pmsg, QMutex *pMutex)
{
pShareMsg = pmsg;
this->pMutex=pMutex;
}
thread_write::~thread_write()
{
}
void thread_write::run()
{
char ch = 'A';
while(1){
pMutex->lock();
for(int i= 0;i<127;i++){
pShareMsg->des[i]=ch;
if(i%20==0){
QThread::sleep(1);
}
}
pMutex->unlock();
QThread::msleep(10);
ch++;
}
}
thread_read::thread_read(msg_struct *pmsg, QMutex *pMutex)
{
pShareMsg = pmsg;
this->pMutex = pMutex;
}
thread_read::thread_read()
{
}
thread_read::~thread_read()
{
}
void thread_read::run()
{
QThread::sleep(1);
while(1){
pMutex->lock();
qDebug()<<"thread read"<<__func__<<" "<
pMutex->unlock();
QThread::sleep(5);
}
}
//widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include"rethread.h"
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
struct msg_struct *pShareMsg;
QMutex *pMutex;
thread_read *pThreadRead;
thread_write *pThreadWrite;
};
#endif // WIDGET_H
//widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
pShareMsg = new struct msg_struct;
pMutex = new QMutex;
pThreadRead = new thread_read(pShareMsg,pMutex);
pThreadWrite = new thread_write(pShareMsg,pMutex);
pThreadWrite->start();
pThreadRead->start();
}
Widget::~Widget()
{
delete ui;
}
信號和槽
在一個線程中定義一個信號,然后將其連接到另一個線程中的槽函數(shù),通過信號的觸發(fā)來調(diào)用槽函數(shù)。這是Qt中最常用的線程間通信方法。這之中有一個線程鐵定是GUI線程。才可以使用信號和槽例如 輸出為 值得注意的是不要在GUI程序中加入sleep睡眠之類的代碼,容易造成程序崩潰。
3.線程間同步
線程同步是指在多線程環(huán)境中,協(xié)調(diào)線程之間的執(zhí)行順序和數(shù)據(jù)共享,確保線程以預期的方式訪問共享資源。同步的主要目的是避免競爭條件(race conditions)和數(shù)據(jù)不一致性。
1.基于互斥量的線程同步QMutex
互斥量可以保證在任意時刻只有一個線程可以訪問共享資源,從而避免競爭條件和數(shù)據(jù)不一致性。定義一把互斥鎖
//widget.h
QMutex *pMutex;
//widget.cpp
pMutex = new QMutex;
上鎖,如果互斥量已經(jīng)被其他線程鎖定,當前線程將被阻塞,直到互斥量可用。
pMutex.lock();
解鎖,訪問共享資源后,線程需要釋放互斥量的鎖,以便其他線程可以訪問該資源。
pMutex.unlock();
嘗試上鎖,函數(shù)tryLock()嘗試鎖定一個互斥量,如果成功鎖定就返回true,如果其他線程已經(jīng)鎖定了這個互斥量就返回false,不等待。有參數(shù)則等待。
pMutex.try_Lock();//括號內(nèi)可以有參數(shù),以毫秒為單位,表示最多等待多少毫秒
2. 基于讀寫鎖的線程同步QReadWriteLock
基于讀寫鎖(Read-Write Lock)的線程同步是一種高效的同步機制,適用于讀多寫少的場景。與互斥鎖不同,讀寫鎖允許多個線程同時讀取共享資源,但在寫入資源時,只允許一個線程進行寫操作,這樣可以提高程序的并發(fā)性能。
定義一把讀寫鎖
//widget.h
QReadWriteLock *pRWLock;
//Widget.cpp
pRWLock = new QReadWriteLock;
pRWLock.lockForRead();//以只讀方式鎖定資源,如果有其他線程以寫入方式鎖定資源,這個函數(shù)會被阻塞pRWLock.lockForWrite();//以寫入方式鎖定資源,如果其他線程以讀或?qū)懛绞芥i定資源,這個函數(shù)會被阻塞pRWLock.unlock();//解鎖它們可以在前面加上try,如tryLockForRead();表示嘗試以讀的方式鎖上資源,括號內(nèi)的參數(shù)可以表示嘗試多少毫秒
3. 基于條件等待的線程同步QWaitCondition
QWaitCondition 提供了一種改進的線程同步方法,QWaitCondition 通過與 QMutex 或QReadWriteLock 結(jié)合使用,可以使一個線程在滿足一定條件時通知其他多個線程,使其他多個線程及時進行響應,這樣比只使用互斥量或讀寫鎖效率要高一些。定義
QMutex mutex;
QReadWriteLock readWriteLock;
QWaitCondition condition;
bool wait(QMutex *lockedMutex, unsigned long time = ULONG_MAX),釋放lockMutex這個互斥信號量。線程進入休眠,等待被喚醒,默認無限等待。若被喚醒則返回true;若超時則返回false。bool wait(QReadWriteLock *lockedReadWriteLock, unsigned long time = ULONG_MAX),釋放lockedReadWriteLock這個讀寫鎖,并讓線程進入等待狀態(tài)直到被喚醒或者超時。默認情況下,無限期等待。若被喚醒則返回true;若超時則返回false。void wakeAll():喚醒所有處于等待狀態(tài)的線程。喚醒順序不確定,由操作系統(tǒng)的調(diào)度策略決定。void wakeOne():喚醒一個處于等待狀態(tài)的線程。具體喚醒哪個線程不確定,由操作系統(tǒng)的調(diào)度策略決定。
4. 基于信號量的線程同步
信號量(QSemaphore)是用于控制多個線程對共享資源的訪問的同步原語。它是一種計數(shù)器,允許你在特定時間允許多個線程同時訪問某個資源。信號量可以用來限制訪問的線程數(shù)。
使用方法
方法名描述參數(shù)返回值構(gòu)造函數(shù)QSemaphore(int initialCount = 1, int maxCount = 1)創(chuàng)建一個信號量,初始計數(shù)和最大計數(shù)。initialCount:初始計數(shù)值maxCount:最大計數(shù)值無基本方法acquire(int num = 1)獲取 num 個資源,若資源不足,線程阻塞。num:需要獲取的資源數(shù)量無release(int num = 1)釋放 num 個資源,增加信號量的計數(shù)器。num:需要釋放的資源數(shù)量無帶超時的方法acquire(int num, unsigned long timeout = ULONG_MAX)獲取 num 個資源,直到超時。num:需要獲取的資源數(shù)量timeout:超時時間(毫秒)bool:成功獲取資源返回 true,超時返回 false檢查方法tryAcquire(int num = 1)嘗試獲取 num 個資源,若資源不足則立即返回。num:需要獲取的資源數(shù)量bool:成功獲取資源返回 true,否則返回 falseavailable() const返回可用資源的數(shù)量。int:可用資源數(shù)量其他方法setCount(int count)設置信號量的計數(shù)器值。count:新的計數(shù)值無maximumCount() const返回信號量的最大值。int:最大值currentCount() const返回當前信號量的計數(shù)值。int:當前計數(shù)值
代碼示例
#include
#include
#include
#include
// 創(chuàng)建一個信號量,初始計數(shù)為3,表示最多同時允許3個線程訪問資源
QSemaphore semaphore(3);
class Worker : public QThread {
public:
void run() override { // 重寫QThread的run()方法,定義線程執(zhí)行的代碼
// 嘗試在1000毫秒內(nèi)獲取一個資源
if (semaphore.tryAcquire(1, 1000)) { // 嘗試獲取一個資源,如果在超時內(nèi)未能獲取,則返回false
qDebug() << "Thread" << QThread::currentThreadId() << "acquired a resource."; // 打印線程獲取資源的消息
QThread::sleep(2); // 模擬工作,線程休眠2秒
qDebug() << "Thread" << QThread::currentThreadId() << "finished working."; // 打印線程完成工作的消息
semaphore.release(); // 釋放一個資源,使其他等待的線程可以獲取到資源
} else {
qDebug() << "Thread" << QThread::currentThreadId() << "could not acquire a resource within timeout."; // 打印超時未獲取資源的消息
}
// 顯示信號量的狀態(tài)
qDebug() << "Current available resources:" << semaphore.available(); // 打印當前可用資源的數(shù)量
semaphore.setCount(5); // 修改信號量的計數(shù)器值為5,增加可用資源
qDebug() << "Max count:" << semaphore.maximumCount(); // 打印信號量的最大計數(shù)值
qDebug() << "Current count:" << semaphore.currentCount(); // 打印當前信號量的計數(shù)值
}
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv); // 創(chuàng)建Qt應用程序?qū)嵗?/p>
// 創(chuàng)建多個Worker線程實例
Worker worker1, worker2, worker3, worker4, worker5;
// 啟動線程
worker1.start();
worker2.start();
worker3.start();
worker4.start();
worker5.start();
// 等待所有線程完成
worker1.wait();
worker2.wait();
worker3.wait();
worker4.wait();
worker5.wait();
return a.exec(); // 進入Qt事件循環(huán)
}
QT睡眠程序
用于讓當前線程休眠或延遲執(zhí)行
QThread::sleep(int sec);//個方法使當前線程休眠指定的秒數(shù)。QThread::msleep(int msec);//這個方法使當前線程休眠指定的毫秒數(shù)。QThread::usleep(int usec);//這個方法使當前線程休眠指定的微秒數(shù)。
柚子快報邀請碼778899分享:開發(fā)語言 QT--線程
精彩內(nèi)容
本文內(nèi)容根據(jù)網(wǎng)絡資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。