c++11 多線程編程——如何實(shí)現(xiàn)線程安全隊(duì)列
線程安全隊(duì)列的接口文件如下:
#include <memory> template<typename T> class threadsafe_queue { public: threadsafe_queue(); threadsafe_queue(const threadsafe_queue&); threadsafe_queue& operator=(const threadsafe_queue&) = delete; void push(T new_value); bool try_pop(T& value); std::shared_ptr<T> try_pop(); void wait_and_pop(T& value); std::shared_ptr<T> wait_and_pop(); bool empty() const; };
push函數(shù)
push()函數(shù)實(shí)現(xiàn)向隊(duì)列添加數(shù)據(jù)的功能。添加數(shù)據(jù)后,使用std::condition_variable的notify_one通知取數(shù)據(jù)時(shí)被阻塞的線程。
void push(T tValue) { std::shared_ptr<T> data(std::make_shared<T>(std::move(tValue))); std::lock_guard<std::mutex> lk(mut); data_queue.push(data); data_con.notify_one(); }
wait_and_pop函數(shù)
wait_and_pop()函數(shù)實(shí)現(xiàn)從隊(duì)列取數(shù)據(jù)的功能,當(dāng)隊(duì)列為空時(shí),線程被掛起,等待有數(shù)據(jù)時(shí)被喚醒。
注意,這兩個(gè)函數(shù)中沒(méi)有使用std::lock_guard,而是使用std::unique_lock,這是為什么呢?
這是因?yàn)閟td::condition_variable的wait函數(shù)會(huì)首先檢測(cè)條件data_queue.empty()是否滿足,如果隊(duì)列為空,wait函數(shù)會(huì)釋放mutex,并被掛起;當(dāng)有新的數(shù)據(jù)進(jìn)入隊(duì)列,std::condition_variable的wait函數(shù)會(huì)被喚醒,重新嘗試獲取mutex,然后檢測(cè)隊(duì)列是否為空,如果隊(duì)列非空,則繼續(xù)向下執(zhí)行。由于函數(shù)的執(zhí)行過(guò)程存在鎖的釋放和重新獲取,所以沒(méi)有使用std::lock_guard,而是選擇了std::unique_lock。
void wait_and_pop(T& value) { std::unique_lock<std::mutex> lk(mut); data_cond.wait(lk,[this]{return !data_queue.empty();}); value=data_queue.front(); data_queue.pop(); } std::shared_ptr<T> wait_and_pop() { std::unique_lock<std::mutex> lk(mut); data_cond.wait(lk,[this]{return !data_queue.empty();}); std::shared_ptr<T> res(std::make_shared<T>(data_queue.front())); data_queue.pop(); return res; }
try_pop函數(shù)
try_pop函數(shù)提供非阻塞調(diào)用下的彈出隊(duì)列(queue)的功能。彈出成功返回true或者非空shared_ptr,失敗則返回false或者nullptr。
bool try_pop(T& value) { std::lock_guard<std::mutex> lk(mut); if(data_queue.empty()) { return false; } value = data_queue.front(); data_queue.pop(); return true; } std::shared_ptr<T> try_pop() { std::lock_guard<std::mutex> lk(mut); if(data_queue.empty()) { return std::shared_ptr<T>(); } std::shared_ptr<T> res(std::make_shared<T>(data_queue.front())); data_queue.pop(); return res; }
empty函數(shù)
bool empty() const { std::lock_guard<std::mutex> lk(mut); return data_queue.empty(); }
這里注意,empty()是const類(lèi)型的成員函數(shù),表明它聲明自己并不改變?nèi)魏纬蓡T變量,但是mutex lock是一個(gè)mutating opertation,所以必須要將mut聲明為mutable類(lèi)型(mutable std::mutex mut)。
完整代碼如下:
#include <queue> #include <memory> #include <mutex> #include <condition_variable> template<typename T> class threadsafe_queue { private: mutable std::mutex mut; std::queue<T> data_queue; std::condition_variable data_cond; public: threadsafe_queue(){} threadsafe_queue(threadsafe_queue const& other) { std::lock_guard<std::mutex> lk(other.mut); data_queue=other.data_queue; } void push(T new_value) { std::lock_guard<std::mutex> lk(mut); data_queue.push(new_value); data_cond.notify_one(); } void wait_and_pop(T& value) { std::unique_lock<std::mutex> lk(mut); data_cond.wait(lk,[this]{return !data_queue.empty();}); value=data_queue.front(); data_queue.pop(); } std::shared_ptr<T> wait_and_pop() { std::unique_lock<std::mutex> lk(mut); data_cond.wait(lk,[this]{return !data_queue.empty();}); std::shared_ptr<T> res(std::make_shared<T>(data_queue.front())); data_queue.pop(); return res; } bool try_pop(T& value) { std::lock_guard<std::mutex> lk(mut); if(data_queue.empty()) return false; value=data_queue.front(); data_queue.pop(); return true; } std::shared_ptr<T> try_pop() { std::lock_guard<std::mutex> lk(mut); if(data_queue.empty()) return std::shared_ptr<T>(); std::shared_ptr<T> res(std::make_shared<T>(data_queue.front())); data_queue.pop(); return res; } bool empty() const { std::lock_guard<std::mutex> lk(mut); return data_queue.empty(); } };
以上就是c++ 如何實(shí)現(xiàn)線程安全隊(duì)列的詳細(xì)內(nèi)容,更多關(guān)于c++ 線程安全隊(duì)列的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)一個(gè)閃爍的圣誕樹(shù)
本文詳細(xì)講解了C語(yǔ)言實(shí)現(xiàn)一個(gè)閃爍的圣誕樹(shù),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12VC實(shí)現(xiàn)Windows多顯示器編程的方法
這篇文章主要介紹了VC實(shí)現(xiàn)Windows多顯示器編程的方法,涉及VC獲取屏幕分辨率及顯示參數(shù)等技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10深入剖析C++中的struct結(jié)構(gòu)體字節(jié)對(duì)齊
要求數(shù)據(jù)內(nèi)存的起始地址的值是某個(gè)數(shù)k的倍數(shù),這就是所謂的內(nèi)存對(duì)齊,本文就來(lái)深入剖析C++中的struct結(jié)構(gòu)體字節(jié)對(duì)齊,需要的朋友可以參考下2016-05-05基于C語(yǔ)言實(shí)現(xiàn)迷宮游戲的示例代碼
這篇文章主要介紹了基于C語(yǔ)言如何實(shí)現(xiàn)簡(jiǎn)單的迷宮游戲,對(duì)于學(xué)習(xí)游戲開(kāi)發(fā)的朋友相信有一定的借鑒價(jià)值,需要的朋友可以參考下2022-05-05C++模擬Linux Shell編寫(xiě)一個(gè)自定義命令
這篇文章主要介紹了C++如何模擬Linux Shell實(shí)現(xiàn)編寫(xiě)一個(gè)自定義命令,本文通過(guò)實(shí)例代碼進(jìn)行命令行解析,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12C/C++動(dòng)態(tài)分配與釋放內(nèi)存的區(qū)別詳細(xì)解析
以下是對(duì)C與C++中動(dòng)態(tài)分配與釋放內(nèi)存的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下2013-09-09