使用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.mzph.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协议可以有效防止远程管理过程中得信息…