使用mutex和條件變量實現信號量

c++提供了互斥量:mutex和條件變量:condition_variable,但是并沒有信號量:semaphore。而linux和windows系統庫會提供的。下面簡單介紹一下信號量的特性,然后給出一個簡單的demo,使用mutex + condition_variable 來實現信號量。
信號量的定義
信號量是一個整數count,提供兩個原子操作:P操作和V操作
P操作(wait操作):count減1;如果count < 0,那么掛起執行線程
V操作(signal操作):count加1;如果count <= 0,那么喚醒一個執行線程
mutex互斥量相當于一把鎖,lock的狀態為0 ,1,也就是lock狀態與unlock狀態。如果現在有多把鎖,數量count最初被設定為n,取1把鎖count–,如果發現鎖的數量小于0,也就是沒有鎖了,此時就需要wait,也可以說是suspend or block,直到別人釋放出一把鎖。取完鎖要還一把鎖,也就是count++,如果發現此時count<=0,說明此時有人在等待鎖,就喚醒一個等待的線程,把鎖給他。
當count = 1時,就相當于mutex了。
如何實現信號量
1、首先需要一個int or long變量作為count;
2、然后由于PV操作是原子操作,所以至少需要一個mutex來保證互斥
3、需要掛起線程,又需要喚醒線程,所以也需要用到condition_variable
代碼

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
namespace Solution1 {class semaphore {private:int count;int wakeups;    // 輔助變量,要喚醒的線程數,初值為0std::mutex mutex;std::condition_variable cond;public:semaphore(int value = 1) : count(value), wakeups(0) {}void wait()  // P操作{std::unique_lock<std::mutex> lock(mutex);if (--count < 0) {cond.wait(lock, [&]()->bool{return wakeups > 0;});--wakeups;}}void signal() // V操作{std::lock_guard<std::mutex> lock(mutex);if (++count <= 0) {++wakeups;cond.notify_one();}}};std::mutex printMutex;Solution1::semaphore ba(0) , cb(0), dc(0);void a(){ba.wait(); // b->astd::lock_guard<std::mutex> lock(printMutex);std::cout << "thread a" <<std::endl;}void b(){cb.wait(); // c->bstd::lock_guard<std::mutex> lock(printMutex);std::cout << "thread b" <<std::endl;ba.signal(); // b->a}void c(){dc.wait(); // d->cstd::lock_guard<std::mutex> lock(printMutex);std::cout << "thread c" <<std::endl;cb.signal(); // c->b}void d(){std::lock_guard<std::mutex> lock(printMutex);std::cout << "thread d" <<std::endl;dc.signal(); // d->c}
};namespace Solution2 {class semaphore {private:int count;std::mutex mutex;std::condition_variable cond;public:semaphore(int value = 1) : count(value){}void wait()  // P操作{std::unique_lock<std::mutex> lock(mutex);if (--count < 0) {cond.wait(lock);}}void signal() // V操作{std::lock_guard<std::mutex> lock(mutex);if (++count <= 0) {cond.notify_one();}}};std::mutex printMutex;Solution1::semaphore ba(0) , cb(0), dc(0);void a(){ba.wait(); // b->astd::lock_guard<std::mutex> lock(printMutex);std::cout << "thread a" <<std::endl;}void b(){cb.wait(); // c->bstd::lock_guard<std::mutex> lock(printMutex);std::cout << "thread b" <<std::endl;ba.signal(); // b->a}void c(){dc.wait(); // d->cstd::lock_guard<std::mutex> lock(printMutex);std::cout << "thread c" <<std::endl;cb.signal(); // c->b}void d(){std::lock_guard<std::mutex> lock(printMutex);std::cout << "thread d" <<std::endl;dc.signal(); // d->c}
};// 測量一個函數的運行時間
template <class T>
void measure(T&& func) {using namespace std::chrono;auto start = system_clock::now();// funcfunc();duration<double> diff = system_clock::now() - start;std::cout << "執行了" << diff.count() << "秒" << std::endl;
}int main()
{measure([](){std::thread th1(Solution1::a), th2(Solution1::b), th3(Solution1::c), th4(Solution1::d);th1.join();th2.join();th3.join();th4.join();std::cout << "ending" << std::endl;});measure([](){std::thread th1(Solution2::a), th2(Solution2::b), th3(Solution2::c), th4(Solution2::d);th1.join();th2.join();th3.join();th4.join();std::cout << "ending" << std::endl;});return 0;
}

在linux系統下運行效果如下:

dyy@dyy-Lenovo-ThinkBook-14-IIL:~/Desktop/HeartBeat$ touch main.cpp
dyy@dyy-Lenovo-ThinkBook-14-IIL:~/Desktop/HeartBeat$ vim main.cpp 
dyy@dyy-Lenovo-ThinkBook-14-IIL:~/Desktop/HeartBeat$ g++ -pthread -o main main.cpp 
dyy@dyy-Lenovo-ThinkBook-14-IIL:~/Desktop/HeartBeat$ ./main 
thread d
thread c
thread b
thread a
ending
執行了0.000541065秒
thread d
thread c
thread b
thread a
ending
執行了0.000292463秒
dyy@dyy-Lenovo-ThinkBook-14-IIL:~/Desktop/HeartBeat$ ./main 
thread d
thread c
thread b
thread a
ending
執行了0.000422226秒
thread d
thread c
thread b
thread a
ending
執行了0.000189556秒
dyy@dyy-Lenovo-ThinkBook-14-IIL:~/Desktop/HeartBeat$ ./main 
thread d
thread c
thread b
thread a
ending
執行了0.000549342秒
thread d
thread c
thread b
thread a
ending
執行了0.000312412秒
dyy@dyy-Lenovo-ThinkBook-14-IIL:~/Desktop/HeartBeat$ ./main 
thread d
thread c
thread b
thread a
ending
執行了0.000521796秒
thread d
thread c
thread b
thread a
ending
執行了0.00043399秒
dyy@dyy-Lenovo-ThinkBook-14-IIL:~/Desktop/HeartBeat$ ./main 
thread d
thread c
thread b
thread a
ending
執行了0.000426875秒
thread d
thread c
thread b
thread a
ending
執行了0.000244544秒
dyy@dyy-Lenovo-ThinkBook-14-IIL:~/Desktop/HeartBeat$ ./main 
thread d
thread c
thread b
thread a
ending
執行了0.000445409秒
thread d
thread c
thread b
thread a
ending
執行了0.000345057秒
dyy@dyy-Lenovo-ThinkBook-14-IIL:~/Desktop/HeartBeat$ ./main 
thread d
thread c
thread b
thread a
ending
執行了0.000377516秒
thread d
thread c
thread b
thread a
ending
執行了0.000258996秒
dyy@dyy-Lenovo-ThinkBook-14-IIL:~/Desktop/HeartBeat$ ./main 
thread d
thread c
thread b
thread a
ending
執行了0.000523052秒
thread d
thread c
thread b
thread a
ending
執行了0.00027911秒
dyy@dyy-Lenovo-ThinkBook-14-IIL:~/Desktop/HeartBeat$ ./main 
thread d
thread c
thread b
thread a
ending
執行了0.000517352秒
thread d
thread c
thread b
thread a
ending
執行了0.000395749秒
dyy@dyy-Lenovo-ThinkBook-14-IIL:~/Desktop/HeartBeat$ ./main 
thread d
thread c
thread b
thread a
ending
執行了0.000488651秒
thread d
thread c
thread b
thread a
ending
執行了0.000392515秒

參考
c++11中信號量(semaphore)的實現 | 陸仁賈
深層次探討mutex與semaphore之間的區別
下面的這個代碼比較復雜:
線程同步之信號量,代碼實現方法2(條件變量+mutex互斥量)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/376796.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/376796.shtml
英文地址,請注明出處:http://en.pswp.cn/news/376796.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2014-07-28 使用Axure RP進行手機端BBS的原型設計

今天是在吾索實習的第14天。因本公司的微信公眾號需要有一個對外的技術交流平臺&#xff0c;所以我們小組打算設計一個手機端的BBS以滿足其要求。首先&#xff0c;我們需要做的是進行數據庫設計與原型設計&#xff0c;然后提交給經理驗收&#xff0c;看看是否合理&#xff0c;是…

jquery exif + lazyload實現延遲加載并顯示相片exif信息

對一個攝影愛好者來說&#xff0c;從高手的作品中學習是非常有用的。而照片的光圈&#xff0c;快門&#xff0c;感光度等信息是關注的重點。 上代碼&#xff1a; 1 <script src"../js/jquery.js" type"text/javascript"></script>2 <script…

undefined reference to `pthread_create‘(linux下Clion使用thread報錯)

完整報錯&#xff1a; [ Build | AsyncLogger | Debug ] /snap/clion/169/bin/cmake/linux/bin/cmake --build /home/dyy/CLionProjects/AsyncLogger/cmake-build-debug --target AsyncLogger -- -j 6 [ 50%] Linking CXX executable AsyncLogger /usr/bin/ld: CMakeFiles/Asy…

UVALive 6257 Chemist's vows --一道題的三種解法(模擬,DFS,DP)

題意&#xff1a;給一個元素周期表的元素符號&#xff08;114種&#xff09;&#xff0c;再給一個串&#xff0c;問這個串能否有這些元素符號組成&#xff08;全為小寫&#xff09;。 解法1&#xff1a;動態規劃 定義&#xff1a;dp[i]表示到 i 這個字符為止&#xff0c;能否有…

.NET開發相關使用工具和框架【轉載】

開發類 visual_studio 2005-2012系列----------語言開發工具 Visio 2003 / Power Desiger -----------建模工具 Dreamweaver_CS5 --------------網頁設計 ExpressionStudio 4 / blend 4 -------------wpf/silverlight設計工具 開發輔助類 SVN 主程序 ---------------文件控制 I…

JAVA數組的定義及用法

數組是有序數據的集合&#xff0c;數組中的每一個元素具有同樣的數組名和下標來唯一地確定數組中的元素。 1. 一維數組 1.1 一維數組的定義 type arrayName[]; type[] arrayName; 當中類型(type)能夠為Java中隨意的數據類型&#xff0c;包含簡單類型組合類型&#xff0c;數組名…

php操作httpsqs

php初始化httpsqs: include_once("httpsqs_client.php");$httpsqs new httpsqs("127.0.0.1", 1218, "mypass123", "utf-8"); php操作httpsqs:常用命令 操作入隊&#xff1a; $result $httpsqs->put(xiongwei2, test1); 獲取隊列中…

異步日志系統設計demo

目錄簡單版本1優化版本1優化版本2對于QPS要求很高或者對性能有一定要求的服務器程序&#xff0c;同步寫日志會對服務的關鍵性邏輯的快速執行和及時響應帶來一定的性能損失&#xff0c;因為寫日志時等待磁盤IO完成工作也需要一定時間。為了減少這種損失&#xff0c;一般采用異步…

js unix時間戳轉換

一、unix時間戳轉普通時間&#xff1a; var unixtime1358932051; var unixTimestamp new Date(unixtime* 1000); commonTime unixTimestamp.toLocaleString(); alert("普通時間為&#xff1a;"commonTime); 二、普通時間轉unix時間戳 var str "2013-01-01 00…

hdu 1025(最長非遞減子序列的n*log(n)求法)

題目鏈接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1025 經典題。。。最長非遞減序列的n*log(n)求法。。。orz... View Code 1 #include<iostream>2 const int N500007;3 using namespace std;4 int city[N];5 int dp[N];//dp[i]保存的是長度為i的最長不降…

消息隊列重要機制講解以及MQ設計思路(kafka、rabbitmq、rocketmq)

目錄《Kafka篇》簡述kafka的架構設計原理&#xff08;入口點&#xff09;消息隊列有哪些作用&#xff08;簡單&#xff09;消息隊列的優缺點&#xff0c;使用場景&#xff08;基礎&#xff09;消息隊列如何保證消息可靠傳輸死信隊列是什么&#xff1f;延時隊列是什么&#xff1…

js判斷手機瀏覽器

最新瀏覽器識別合并。 demo&#xff1a;http://v.qq.com -> http://v.qq.com/h5    http://v.qq.com/ -> http://v.qq.com/h5    http://v.qq.com/h5 -> http://v.qq.com/h5 <script type"text/javascript"> (function(W){ …

數據庫歸檔模式

1、在sys身份下登陸oracle&#xff0c;執行命令archive log list; SQL> archive log list; Database log mode Archive Mode Automatic archival Enabled Archive destination USE_DB_RECOVERY_FILE_DEST Oldest online log sequence …

轉載|網絡編程中阻塞式函數的底層邏輯

逛知乎看到的&#xff0c;覺得寫的挺透徹的&#xff0c;轉載一下&#xff0c;原文鏈接&#xff1a;Unix網絡編程里的阻塞是在操作系統的內核態創建一個線程來死循環嗎&#xff1f; 原文以阻塞式的recv函數作為講解&#xff0c;但是所有阻塞式的api底層邏輯基本相通。 下面是正文…

把txt文件中的json字符串寫到plist文件中

- (void)json2Plist {NSString *filePath [self applicationDocumentsDirectoryFileName:"json"];NSMutableArray *tempArray [[NSMutableArray alloc] initWithContentsOfFile:filePath];//第一次添加數據時,數組為空if (tempArray.count 0) {tempArray [NSMuta…

樹的存儲結構2 - 數據結構和算法42

樹的存儲結構 讓編程改變世界 Change the world by program 孩子表示法 我們這次換個角度來考慮&#xff0c;由于樹中每個結點可能有多棵子樹&#xff0c;可以考慮用多重鏈表來實現。 就像我們雖然有計劃生育&#xff0c;但我們還是無法確保每個家庭只養育一個孩子的沖動&a…

海量數據去重

海量數據去重 一個文件中有40億條數據&#xff0c;每條數據是一個32位的數字串&#xff0c;設計算法對其去重&#xff0c;相同的數字串僅保留一個&#xff0c;內存限制1G. 方法一&#xff1a;排序 對所有數字串進行排序&#xff0c;重復的數據傳必然相鄰&#xff0c;保留第一…

Sharepoint 2013 發布功能(Publishing features)

一、默認情況下&#xff0c;在創建網站集時&#xff0c;只有選擇的模板為‘ Publishing Portal&#xff08;發布門戶&#xff09;’與‘ Enterprise Wiki&#xff08;企業 Wiki&#xff09;’時才默認啟用發布功能&#xff0c;如下圖所示&#xff1a; 二、發布功能包含兩塊&…

【原】android啟動時白屏或者黑屏的問題

解決應用啟動時白屏或者黑屏的問題 由于Activity只能到onResume時&#xff0c;才能展示到前臺&#xff0c;所以&#xff0c;如果為MAIN activity設置背景的話&#xff0c;無論onCreate-onResume速度多快&#xff0c;都會出現短暫的白屏或者黑屏 其實解決的辦法很簡單&#xff0…

【草稿】windows + vscode 遠程開發

主要分為三個步驟&#xff1a; 1、開啟openssh服務 2、通過ssh命令連接到遠程服務器 3、通過vscode連接遠程服務器進行開發調試 ssh概念 SSH是較可靠&#xff0c;專為遠程登陸會話和其他網絡服務提供安全性得協議&#xff0c;利用ssh協議可以有效防止遠程管理過程中得信息…