C++11多线程编程——信号量的实现

news/2024/10/5 18:17:38/

一、为何需要信号量

信号量用来干嘛的呢?搜寻答案的话,很多人都会告诉你主要用于线程同步的,意思就是线程通信的。简单来说,比如我运行了2个线程A和B,但是我希望B线程在A线程之前执行,那么我们就可以用信号量来处理。有些人可能会疑惑,那么麻烦干嘛?你不是要B线程先执行吗?那么我让A线程休眠一点时间不就可以了吗?没错,这个思路是可以的,但是如果B线程也因为某些原因(比如硬件,操作系统的原因)导致延缓执行了,这该怎么办?到底A线程该休眠多少时间合适呢?所以正确的做法就是在B线程阻塞,A线程去唤醒这个阻塞线程。

看到这儿,看过我前面文章的朋友可能一眼就看出来了这个不就是前面讲的生产消费者模型提到的用法吗?

没错,信号量的实现也是靠条件变量和互斥锁。

所以虽然C++中并没有在语言级别上支持信号量,但同样的我们可以利用以上两个来自己实现一个。

这里我也不得不提一句,条件变量和互斥锁组合使用真的非常强大,生产消费者模型中用到了,线程池中用到了,现在说的信号量也用到了,所以大家一定要好好掌握条件变量和互斥锁的使用,它们俩是你在多线程世界中纵横捭阖的利剑。

二、信号量的实现

那么我们如何用C++来实现一个信号量呢?

#ifndef _SEMAPHORE_H
#define _SEMAPHORE_H
#include <mutex>
#include <condition_variable>
using namespace std;class Semaphore
{
public:Semaphore(long count = 0) : count(count) {}//V操作,唤醒void signal(){unique_lock<mutex> unique(mt);++count;if (count <= 0)cond.notify_one();}//P操作,阻塞void wait(){unique_lock<mutex> unique(mt);--count;if (count < 0)cond.wait(unique);}private:mutex mt;condition_variable cond;long count;
};
#endif

信号量里面用到了一个叫PV操作的东西,P操作时阻塞,一般用wait()函数,V操作是唤醒,一般用singal()函数,至于不叫WS操作,反而为什么叫PV操作呢?网上说是因为提出这一系统方法的人狄克斯特拉用荷兰文定义的,因为在荷兰文中,通过叫passeren,释放叫vrijgeven,PV操作因此得名。对我们来说,这些也没有太大的意义,记住这些定义就好了,毕竟定义这种东西,是不以我们的意志为转移的。

写好了信号量的接口,那我们如何使用这个信号量呢?这个就需要我们在外部写一个多线程的调用函数来调用。

#include "semaphore.h"
#include <thread>
#include <iostream>
using namespace std;Semaphore sem(0);void funA()
{sem.wait();//do somethingcout << "funA" << endl;
}void funB()
{this_thread::sleep_for(chrono::seconds(1));//do somethingcout << "funB" << endl;sem.signal();
}int main()
{thread t1(funA);thread t2(funB);t1.join();t2.join();
}

三、信号量解析

这里我们想让funB线程运行,然后再运行funA,多线程是通过时间片轮询来执行的。

假设先开始跑funA,执行到sem.wait()的时候,进入wait函数可知,count减1,小于0,会发生阻塞,等待其他线程唤醒。

然后就会切换到funB,这里即使休眠了1秒也不会切换到funA,因为那边阻塞了,没有其他线程唤醒的话就会一直阻塞。funB休眠完之后,就会打印出结果,然后执行sem.signal(),进入signal函数可知,count加1,小于等于0,会唤醒其他阻塞的线程。

然后再切到funA,执行后面的操作,打印出结果。

所以这个就一定能保证funB先执行,funA后执行。当然前提是初始化信号量对象的时候,要初始化为0。

Semaphore sem(0);

信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作。像这里funB完成任务之后就通过信号量的PV操作告诉funA线程可以开始任务了。

最后需要注意的是,信号量不仅可以用于进程也可用于线程,它比条件变量要复杂很多,条件变量仅限于线程内使用,至于进程间如何使用信号量通信,后期我们在讨论。


http://www.ppmy.cn/news/58484.html

相关文章

安卓学习内容记录(笔记,供学习回溯)

安卓工程中那些文件被称为资源文件 转载于https://zhuanlan.zhihu.com/p/415494152 目录资源类型animator/用于定义属性动画的 XML 文件anim/用于定义渐变动画的 XML 文件。&#xff08;属性动画也可保存在此目录中&#xff0c;但为了区分这两种类型&#xff0c;属性动画首选…

QT 中的多线程之继承 Thread

文章目录 1. 概述2. UML 类的关系图3. 代码&#xff1a;4. 运行结果及说明5. 结语 1. 概述 任何继承于QThread的线程都是通过继承 QThread 的run函数来实现多线程的&#xff0c;因此&#xff0c;必须重写QThread的run函数&#xff0c;把复杂逻辑写在QThread的run函数中。然后在…

常见的10个SQL语句性能优化策略

SQL语句性能优化策略 1. 为 WHERE 及 ORDER BY 涉及的列上建立索引 对查询进行优化&#xff0c;应尽量避免全表扫描&#xff0c;首先应考虑在 WHERE 及 ORDER BY 涉及的列上建立索引 2. where中使用默认值代替null 应尽量避免在 WHERE 子句中对字段进行 NULL 值判断&#xff0…

【网站架构】Nginx 4层、7层代理配置,正向代理、反向代理详解

大家好&#xff0c;欢迎来到停止重构的频道。 本期我们讨论网络代理。 在往期《大型网站 安全性》介绍过&#xff0c;出于网络安全的考虑&#xff0c;一般大型网站都需要做网络区域隔离&#xff0c;以防止攻击者直接操控服务器。 网站系统的应用及数据库都会放在这个网络安全…

轻松搭建自己的ChatGPT聊天机器人,让AI陪你聊天!

随着人工智能技术的发展&#xff0c;聊天机器人已经成为了我们生活中的一部分。无论是在客服机器人上还是智能助手上&#xff0c;聊天机器人都能够给我们带来真正的便利和快乐。现在&#xff0c;你也可以轻松搭建自己的ChatGPT聊天机器人&#xff0c;和它天马行空地聊天&#x…

java 多用户即时通信系统的实现 万字详解

目录 前言 一、拾枝杂谈 1.项目开发大体流程 : 2.多用户即时通信系统分析 : 1 需求分析 2 整体分析 二、用户登录 1.准备工作 : 2.客户端 : 1 菜单界面 2 登录验证 3 线程创建 4 线程管理 3.服务端 : 1 用户验证 2 线程创建 3 线程管理 4.登录测试 : 三、在线列表 1.…

对模式的迷信,大部分是幻觉和妄想

对模式的迷信&#xff0c;大部分是幻觉和妄想 往往有严重的投机心理 郑翔洲&#xff0c;所谓模式设计专家 还是有点虚&#xff0c;仅供一点参考 说苹果、说华为、说小米这些总结都是事后诸葛亮 趣讲大白话&#xff1a;商业模式被妖魔化 【趣讲信息科技153期】 ****************…

【网络】网络基础协议概念IPMAC地址

文章目录 网络基础网络的发展历程网络在哪里的问题网络协议栈各部分所处位置&#xff1a;网络协议栈各层的作用网络协议栈分层的目的 网络协议的概念 网络协议协议分层的好处理解各层之间直接通信OSI七层模型TCP/IP五层&#xff08;或四层&#xff09;模型 网络传输基本流程同局…