日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

QT学习:多线程控制

發布時間:2024/9/30 c/c++ 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 QT学习:多线程控制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

實現線程的互斥與同步常使用的類有QMutex、QMutexLocker、QReadWriteLocker、QReadLocker、
QWriteLocker、QSemaphore和QWaitCondition。
下面舉一個例子加以說明:

class Key { public: Key() {key=0;} int creatKey() {++key; return key;} int value()const {return key;} private: int key; };

在多線程環境下,這個類是不安全的,因為存在多個線程同時修改私有成員key,其結果是不可預知
的。
雖然Key類產生主鍵的函數creatKey()只有一條語句執行修改成員變量key的值,但是C++的“++”操作符
并不是原子操作,通常編譯后,它將被展開成為以下三條機器命令:
(1)將變量值載入寄存器。
(2)將寄存器中的值加1。
(3)將寄存器中的值寫回主存。

一、互斥量

1、QMutex類

QMutex類的lock()函數用于鎖住互斥量。如果互斥量處于解鎖狀態,則當前線程就會立即抓住并鎖定它,否則當前線程就會被阻塞,直到持有這個互斥量的線程對它解鎖。線程調用lock()函數后就會持有這個互斥量,直到調用unlock()操作為止。 QMutex類還提供了一個tryLock()函數。如果互斥量已被鎖定,則立即返回。 例如:

class Key { public: Key() {key=0;} int creatKey() { mutex.lock(); ++key; return key; mutex. unlock();} int value()const { mutex.lock(); return key; mutex.unlock();} private: int key; QMutex mutex; };

2、QMutexLocker類

Qt提供的QMutexLocker類可以簡化互斥量的處理,它在構造函數中接收一個QMutex對象作為參數并將其鎖定,在析構函數中解鎖這個互斥量,這樣就解決了以上問題。
例如:

class Key { public: Key() {key=0;} int creatKey() { QmutexLocker locker(&mutex); ++key; return key; } int value()const { QmutexLocker locker(&mutex); return key; } private: int key; QMutex mutex; };

locker()函數作為局部變量會在函數退出時結束其作用域,從而自動對互斥量mutex解鎖。

二、信號量

信號量可以理解為對互斥量功能的擴展,互斥量只能鎖定一次而信號量可以獲取多次,它可以用來保護一定數量的同種資源。信號量的典型用例是控制生產者/消費者之間共享的環形緩沖區。 生產者/消費者實例中對同步的需求有兩處:
(1)如果生產者過快地生產數據,將會覆蓋消費者還沒有讀取的數據。
(2)如果消費者過快地讀取數據,將越過生產者并且讀取到一些過期數據。
針對以上問題,有兩種解決方法:
(1)首先使生產者填滿整個緩沖區,然后等待消費者讀取整個緩沖區,這是一種比較笨拙的方 法。
(2)使生產者和消費者線程同時分別操作緩沖區的不同部分,這是一種比較高效的方法。
具體使用方法見如下代碼:
(1)在源文件“main.cpp”中添加的具體實現代碼如下:

#include <QCoreApplication> #include <QSemaphore> #include <QThread> #include <stdio.h> const int DataSize=1000; const int BufferSize=80; int buffer[BufferSize]; //首先,生產者向buffer中寫入數據,直到它到達終點,然后從起點重新開始覆蓋已經存在的數據。消費者讀取前者生產的數據,在此處每個int字長都被看成一個資源,實際應用中常會在更大的單位上進行操作,從而減少使用信號量帶來的開銷。 QSemaphore freeBytes(BufferSize); // freeBytes信號量控制可被生產者填充的緩沖區部分,被初始化為BufferSize(80),表示程序一開始有BufferSize個緩沖區單元可被填充。 QSemaphore usedBytes(0); // usedBytes信號量控制可被消費者讀取的緩沖區部分,被初始化為0, 表示程序一開始時緩沖區中沒有數據可供讀取。

(2)Producer類繼承自QThread類,作為生產者類,其聲明如下:

class Producer : public QThread { public: Producer(); void run(); };

Producer構造函數中沒有實現任何內容:

Producer::Producer() { }

Producer::run()函數的具體實現代碼如下:

void Producer::run() { for(int i=0;i<DataSize;i++) { freeBytes.acquire(); //生產者線程首先獲取一個空閑單元,如果此時緩沖區被消費者尚未讀取的數據填滿,對此函數的調用就會阻塞,直到消費者讀取了這些數據為止。 buffer[i%BufferSize]=(i%BufferSize); //一旦生產者獲取了某個空閑單元,就使用當前的緩沖區單元序號填寫這個緩沖區單元。 usedBytes.release(); //調用該函數將可用資源加1,表示消費者此時可以讀取這個剛剛填寫的單元了。 } }

release(n)函數用于釋放n個資源。
(3)Consumer類繼承自QThread類,作為消費者類,其聲明如下:

class Consumer : public QThread { public: Consumer(); void run(); };

Consumer構造函數中沒有實現任何內容:

Consumer::Consumer() { }

Consumer::run()函數的具體實現代碼如下:

void Consumer::run() { for(int i=0;i<DataSize;i++) { usedBytes.acquire(); //消費者線程首先獲取一個可被讀取的單元,如果緩沖區中沒有包含任何可以讀取的數據,對此函數的調用就會阻塞,直到生產者生產了一些數據為止。fprintf(stderr,"%d",buffer[i%BufferSize]); //一旦消費者獲取了這個單元,會將這個單元的內容打印出來。 if(i%16==0&&i!=0) fprintf(stderr,"\n"); freeBytes.release(); //調用該函數使得這個單元變為空閑,以備生產者下次填充。 }fprintf(stderr,"\n"); }

(4)main()函數的具體內容如下:

int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Producer producer; Consumer consumer; /* 啟動生產者和消費者線程 */ producer.start(); consumer.start(); /* 等待生產者和消費者各自執行完畢后自動退出 */ producer.wait(); consumer.wait(); return a.exec(); }

(5)最終運行結果如下圖所示:

總結

以上是生活随笔為你收集整理的QT学习:多线程控制的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。