当前位置: 首页 > news >正文

Linux入门之多线程|线程的同步|生产消费模型

文章目录

一、多线程的同步

1.概念

2.条件变量

2.1条件变量概念

2.2条件变量接口

1.条件变量初始化

2.等待条件满足

3.唤醒等待

3.销毁条件变量

2.3条件变量demo

二、生产消费模型

1.生产消费模型

2.基于BlockQueue的生产者消费者模型

3.基于C++用条件变量和互斥锁实现一个生产消费模型

4.信号量

1.信号量概念

2.信号量接口

1.初始化信号量

2.等待信号量(P操作 --)

3.发布信号量(V操作 ++)

4.销毁信号量

5.环形生产者消费者模型



当一个线程互斥地访问某个变量时,它发现可能再其他线程改变状态之前,它被挂起。

例如一个线程访问队列,发现队列为空,它只能等待。直到其他线程将一个节点加入到队列中,这种情况就需要用到条件变量。

一、多线程的同步

1.概念

在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源从而有效避免饥饿问题,叫做同步。

2.条件变量

2.1条件变量概念

条件变量是线程同步的一种手段,如果只有一个线程,条件不满足,一直等待下去都不会满足,所以必须要有一个线程通过某些操作,改变共享变量,使得原来的不满足条件变的满足,并且友好通知等待在条件变量上的线程。

条件变量不会无缘无故满足,必然牵扯到共享数据的变化,所以一定需要用锁来保护,没有锁就无法安全的获取和修改共享数据

2.2条件变量接口

1.条件变量初始化

int pthread_cond_init(pthread_cond_t * restrict cond,const pthread_condattr_t * restrict attr);参数:cond 要初始化的条件变量attr:NULL

2.等待条件满足

int pthread_cond_wait(pthread_cond_t * restrict cond,pthread_mutex_t * restrict mutex);参数:cond: 要在这个条件变量上等待mutex:互斥量,等待的时候要释放掉这个锁

3.唤醒等待

int pthread_cond_broadcast(pthread_cond_t * cond);
int pthread_cond_signal(pthread_cond_t * cond);

3.销毁条件变量

int pthread_cond_destroy(pthread_cond_t * cond);

2.3条件变量demo

#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<cstdio>
#include<string>
using namespace std;const int num = 5;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void *active(void *args)
{string name = static_cast<const char*>(args);while(true){pthread_mutex_lock(&mutex);pthread_cond_wait(&cond,&mutex);// 在调用的时候,会自动释放锁cout<<name<<" activing..."<<endl;pthread_mutex_unlock(&mutex);}}
int main()
{pthread_t tids[num];for(int i = 0; i<num;i++){char * name = new char[32];snprintf(name,32,"thread-%d",i+1);pthread_create(tids+i,nullptr,active,name);}sleep(3);while(true){cout<<"main thread wakeup thread"<<endl;pthread_cond_signal(&cond);sleep(1);}for(int i = 0; i<num;i++){pthread_join(tids[i],nullptr);}}

二、生产消费模型

1.生产消费模型

生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。

2.基于BlockQueue的生产者消费者模型

在多线程编程中阻塞队列 (Blocking Queue) 是一种常用于实现生产者和消费者模型的数据结构。其与普通的队列区别在于,当队列为空时,从队列获取元素的操作将会被阻塞,直到队列中被放入了元素;当队列满时,往队列里存放元 素的操作也会被阻塞,直到有元素被从队列中取出(以上的操作都是基于不同的线程来说的,线程在对阻塞队列进程 操作时会被阻塞。

3.基于C++用条件变量和互斥锁实现一个生产消费模型

需求:使用条件变量和互斥锁实现一个生产消费模型。生产消费模型是一个队列,如上图,这里使用stl中的队列,先实现单生产单消费,一个线程负责生产,一个线程负责消费。这两个线程需要访问同一个队列,所以需要一把锁。在线程挂起的时候,还需要有信号告诉线程现在条件满足了,所以要使用两个条件变量,分别通知生产和消费线程转为就绪态。

实现:将这个模型封装成一个类,两个线程去访问的时候,队列非满,就可以生产,往队列里push数据,队列中数据非空,就可以消费,从队列里pop数据。所以需要两个接口push和pop,调试成功后,最后使用多生产多消费实现。实现代码如下:

//blockqueue.hpp 声明,方法,定义在一个文件中const int gcap = 5;
template<class T>
class blockQueue
{public://构造blockQueue(const int cap = gcap):_cap(cap),{pthread_mutex_init(&_mutex,nullptr);pthread_cond_init(&_consumerCond,nullptr);pthread_cond_init(&_productorCond,nullptr);}bool isFull() {return _q.size() == _cap;}bool isEmpty() { return _q.empty()};//将数据塞进队列 生产void push(const T & in){pthread_mutex_lock(&_mutex);//注意这里不要用if,可能会误唤醒while(isFull()){//在当前的条件下休眠,就注定了要释放锁,让别的线程去竞争锁//休眠,就是被os切走了,醒来之后又要重新申请锁pthread_cond_wait(&_productorCond,&_mutex);  }//如果没满,就让他继续生产_q.push(in);//生产之后,让消费者来消费,唤醒消费的线程 再释放自己手中的锁pthread_cond_signal(&_consumerCond);pthread_mutex_unlock(&_mutex);}//队列非空 消费  void pop(){pthread_mutex_lock(&_mutex);//判断队列是否为空while(isEmpty()){//空的话,在当前条件下休眠pthread_cond_wait(&_consumerCond,&_mutex);}//非空 开始消费 并且唤醒生产者 可以生产了pthread_cond_signal(&_productorCond);pthread_mutex_unlock(&_mutex);}//析构~blockQueue(){//释放锁和两个信号量 队列是一个临时变量可以不用在这里释放pthread_mutex_destroy(&mutex);pthread_cond_destroy(&_consumerCond);pthread_cond_destroy(&_productorCond);}private:std::queue<T> _q;int _cap; //队列中的容量pthread_mutex_t _mutex;pthread_cond_t _consumerCond; //消费者对应的条件变量,如果队列中数据为空,waitpthread_cond_t _productorCond; //生产者对应的条件变量,如果队列中数据为满,wait
};

4.信号量

1.信号量概念

        POSIX信号量和System V 信号量作用相同,都是用于同步操作,达到无冲突访问共享资源的目的。但是POSIX可以用于线程间同步。信号量本质就是用来描述临界资源中的数量

        sem = 1,就只有0/1两种状态,就是互斥锁。

        多元信号量:每个线程,在访问对应资源时,先申请信号量。申请成功,就表示现在可以时候该资源。申请失败,就目前无法访问。

2.信号量接口

#include<semaphore.h>

1.初始化信号量

int sem_init(sem_t * sem, int pshared ,unsiged int value);参数:pshared 0 表示线程间共享,非0 表示进程间共享value:信号量初始值

2.等待信号量(P操作 --)

int sem_wait(sem_t * sem);

3.发布信号量(V操作 ++)

int sem_post(sem_t * sem);

4.销毁信号量

int sem_destroy(sem_t * sem);

5.环形生产者消费者模型 

       环形队列采用数组模拟,用%运算来模拟环状特性。在为空/满的时候要保证游戏规则,在非空非满的时候保证并发。

环形结构起始状态和结束状态都是一样的,不容易判断是空还是满,所以通过加计数器或者标记位来判断。另外也可以预留一个空的位置,作为满的状态。

但是我们现在有信号量这个计数器,就可以进行多线程间的同步过程。

生产者关心这个空间是否满了,消费者关心是否有数据。环形队列只要访问不同的区域,生产和消费行为可以同时进行。

需求:生产消费模型是一个队列,使用数组模拟,同时需要两个线程,生产线程和消费线程。要维护3种关系:生产者和生产者,消费者和消费者,生产者和消费者之间的关系。其中生产者和生产者,需要互斥。消费者和消费者同样互斥。生产者和消费者,需要先生产再消费,所以需要同步。同时,访问同一个队列(共享资源)需要互斥关系。

实现:将队列封装成类,用数组模拟实现。类需要暴露的接口就是pushpop,即实现p操作和v操作。同时要知道这个队列的大小定义两个信号量,一个是消费者关心的,一个是生产者关心。申请信号量成功之后,也要知道生产和消费此刻对应队列中的位置,就是具体维护哪个区域。即两个下标。申请自己关心的资源,互相V对方的资源

static const int N = 5;template<class T>
class RingQueue
{private:void P(sem_t &s){sem_wait(&s);}void V(sem_t &s){sem_post(&s);}public://构造RingQueue(int num = N):_ring(num),_cap(num){sem_init(&_data_sem,0,0);        sem_init(&_space_sem,0,num);//刚开始都为0_c_step = _p_step = 0;}void push(const T &in){//申请P(_space_sem);_ring[_p_step++] = in;_p_step %= _cap;V(_data_sem);}void pop(T * out){P(_data_sem);*out = _ring[_c_step++];_c_step &= _cap;V(_spcae_sem);}~RingQueue(){sem_destroy(&_data_sem);sem_destroy(&_space_sem);}private:std::vector<T> _ring;int _cap;sem_t _data_sem;sem_t _space_sem;int _c_step;int _p_step;
};

相关文章:

Linux入门之多线程|线程的同步|生产消费模型

文章目录 一、多线程的同步 1.概念 2.条件变量 2.1条件变量概念 2.2条件变量接口 1.条件变量初始化 2.等待条件满足 3.唤醒等待 3.销毁条件变量 2.3条件变量demo 二、生产消费模型 1.生产消费模型 2.基于BlockQueue的生产者消费者模型 3.基于C用条件变量和互斥锁实…...

MATLAB解析和保存ini文件

1. 将ini文件转换成struct结构体 function data ini2struct(filename)fid fopen(filename, r);if fid -1error(Unable to open file %s., filename);enddata struct();section ;while ~feof(fid)line fgetl(fid);line strtrim(line);% 如果是注释行或者空行&#xff0c…...

模型压缩-对模型结构进行优化

模型压缩-对模型结构进行优化 概述 模型压缩通常都是对推断过程而言&#xff0c;训练过程的计算代价通常不考虑&#xff0c;因为GPU可以快速完成任意复杂度模型的训练对于推断过程来说&#xff0c;模型应用才是对于速度敏感的场景多数情况下 希望使用尽可能少的能耗完成京可能…...

软件工程课件

软件工程 考点概述软件工程概述能力成度模型能力成熟度模型集成软件过程模型逆向工程![ ](https://img-blog.csdnimg.cn/425cea8190fb4c5ab2bf7be5e2ad990e.png) 考点概述 重点章节 软件工程概述 之前老版教程的&#xff0c;之前考过 能力成度模型 记忆 能力等级 和 特点 能力…...

基于ADS的marx雪崩电路设计-设计实践(射频脉冲源)

基于ADS的marx雪崩电路设计-设计实践&#xff08;射频脉冲源&#xff09; 设计一个ns级别的脉冲源&#xff0c;属于是半路转行的&#xff0c;虽然不了解具体原理但是也可以进行设计。具体的设计理论以及优化方法将在之后进行讨论. 参考文献&#xff1a;基于Marx电路的亚纳秒级…...

X86_64函数调用汇编程序分析

X86_64函数调用汇编程序分析 1 X86_64寄存器使用标准2 对应代码的分析2.1 main函数及其对应的汇编程序2.1.1 main的C代码实现2.1.2 main函数对应汇编及其分析2.1.3 执行完成之后栈的存放情况 2.2 test_fun_a函数及其对应的汇编程序2.2.1 test_fun_a函数的C实现2.2.2 test_fun_a…...

Vue3【Provide/Inject】

前言 自从使用了Provide/Inject代码的组织方式更加灵活了&#xff0c;但是这个灵活性的增加伴随着代码容错性的降低。我相信只要是真的在项目中引入Provide/Inject的同学&#xff0c;一定一定有过或者正在经历下面的状况&#xff1a; 注入名&#xff08;Injection key&#x…...

Go-Python-Java-C-LeetCode高分解法-第四周合集

前言 本题解Go语言部分基于 LeetCode-Go 其他部分基于本人实践学习 个人题解GitHub连接&#xff1a;LeetCode-Go-Python-Java-C Go-Python-Java-C-LeetCode高分解法-第一周合集 Go-Python-Java-C-LeetCode高分解法-第二周合集 Go-Python-Java-C-LeetCode高分解法-第三周合集 本…...

vue路由

一、声明式导航-导航链接 1.需求 实现导航高亮效果 如果使用a标签进行跳转的话&#xff0c;需要给当前跳转的导航加样式&#xff0c;同时要移除上一个a标签的样式&#xff0c;太麻烦&#xff01;&#xff01;&#xff01; 2.解决方案 vue-router 提供了一个全局组件 router…...

最强的AI视频去码图片修复模型:CodeFormer

目录 1 CodeFormer介绍 1.1 CodeFormer解决的问题 1.2 人脸复原的挑战 1.3 方法动机 1.4 模型实现 1.5 实验结果 2 CodeFormer部署与运行 2.1 conda环境安装 2.2 运行环境构建 2.3 模型下载 2.4 运行 2.4.1 人脸复原 ​编辑​编辑 2.4.2 全图片增强 2.4.3 人脸颜色…...

jenkins自动化部署安装

一、准备工作 1、安装jdk # 1、下载准备jdk包(也可以用docker安装) wget ... # 2、直接解压到,无需安装 unzip ...2、安装maven # 1、下载准备maven压缩包 wget ... # 2、直接解压,无需安装 unzip ... # 3、修改setting.xml&#xff0c;修改localRepository和MIRROR镜像地址…...

如何调用Zabbix API获取主机信息

自Zabbix 1.8版本被引进以后&#xff0c;Zabbix API开始扮演着越来越重要的角色&#xff0c;它可以为批量操作、第三方软件集成以及其他应用提供可编程接口。 在运维实践中&#xff0c;Zabbix API还有更多巧妙的应用。 面对规模庞大的监控设备&#xff0c;可能会出现某台机器发…...

批量执行redis命令总结

目录 批量执行redis命令方式1: redis-cli直接执行方式2:通过redis-cli和xargs等命令 批量执行redis命令 方式1: redis-cli直接执行 redis-cli command param redis-cli本身支持单个命令执行省略了连接参数操作的key等相关数据&#xff0c;可以通过线下获取或通过keys scan等命…...

命令行git联网失败,但是实际可以联网

最近下载代码的时候发现总是告诉我连不上github的网页&#xff0c;但是我自己通过浏览器又可以上网&#xff0c;找了半天发现这个方法可以。 记录下这个代理 打开git bash 执行以下命令&#xff1a; git config --global http.proxy http://127.0.0.1:7890 git config --glob…...

网络编程套接字,Linux下实现echo服务器和客户端

目录 1、一些网络中的名词 1.1 IP地址 1.2 端口号port 1.3 "端口号" 和 "进程ID" 1.4 初始TCP协议 1.5 UDP协议 2、socket编程接口 2.1 socket 常见API 2.2 sockaddr结构 3、简单的网络程序 3.1 udp实现echo服务器和客户端 3.1.1 echo服务器实…...

java+ssh+mysql智能化办公管理系统

项目介绍&#xff1a; 本系统为基于jspsshmysql的OA智能办公管理系统&#xff0c;包含管理员、领导、员工角色&#xff0c;功能如下&#xff1a; 管理员&#xff1a;公告信息&#xff1b;工作计划&#xff1b;公司资料&#xff1b;部门管理&#xff1b;员工管理&#xff1b;员…...

网络层抓包tcpdump

sudo tcpdump -i eth0 -s 0 -nn host iphost -w xxx.pcap 这段代码使用了命令行工具 tcpdump&#xff0c;用于在Linux系统上捕获网络数据包。让我详细介绍一下这段代码的含义和 tcpdump 的用法&#xff1a; 代码含义&#xff1a; sudo: 使用超级用户权限执行 tcpdump 命令&am…...

QT之形态学操作

形态学操作包含以下操作&#xff1a; 腐蚀 (Erosion)膨胀 (Dilation)开运算 (Opening)闭运算 (Closing)形态梯度 (Morphological Gradient)顶帽 (Top Hat)黑帽(Black Hat) 其中腐蚀和膨胀操作是最基本的操作&#xff0c;其他操作由这两个操作变换而来。 腐蚀 用一个结构元素…...

15、监测数据采集物联网应用开发步骤(11)

源码将于最后一遍文章给出下载 监测数据采集物联网应用开发步骤(10) 程序自动更新开发 前面章节写了部分功能模块开发&#xff1a; 日志或文本文件读写开发;Sqlite3数据库读写操作开发;定时器插件化开发;串口(COM)通讯开发;TCP/IP Client开发;TCP/IP Server 开发;modbus协议…...

Pygame中Trivia游戏解析6-2

3.1.2 读取保存题目的文件 在Trivia类的__init__()方法中&#xff0c;对各变量初始化完成之后&#xff0c;读取保存题目的文件&#xff0c;代码如下所示。 f open(filename, "r", encodingutf8) trivia_data f.readlines() f.close() 其中&#xff0c;open()函数…...

java 实现命令行模式

命令模式是一种行为设计模式&#xff0c;它允许您将请求封装为对象&#xff0c;以便您可以将其参数化、队列化、记录和撤销。在 Java 中实现命令模式涉及创建一个命令接口&#xff0c;具体命令类&#xff0c;以及一个接收者类&#xff0c;该接收者类执行实际操作。下面是一个简…...

A - Orac and Models(最长上升子序列——加强版)

There are nn models in the shop numbered from 11 to nn, with sizes s_1, s_2, \ldots, s_ns1​,s2​,…,sn​. Orac will buy some of the models and will arrange them in the order of increasing numbers (i.e. indices, but not sizes). Orac thinks that the obtai…...

【python手写算法】逻辑回归实现分类(含公式推导)

公式推导&#xff1a; 代码实现&#xff1a; # codingutf-8 import matplotlib.pyplot as plt import numpy as npdef f(w1,x1,w2,x2,b):zw1*x1w2*x2breturn 1/(1np.exp(-z)) if __name__ __main__:X1 [12.46, 0.25, 5.22, 11.3, 6.81, 4.59, 0.66, 14.53, 15.49, 14.43,2.1…...

【2023高教社杯数学建模国赛】ABCD题 问题分析、模型建立、参考文献及实现代码

【2023高教社杯数学建模国赛】ABCD题 问题分析、模型建立、参考文献及实现代码 1 比赛时间 北京时间&#xff1a;2023年9月7日 18:00-2023年9月10日20:00 2 思路内容 可以参考我提供的历史竞赛信息内容&#xff0c;最新更新我会发布在博客和知乎上&#xff0c;请关注我获得最…...

yum安装mysql5.7散记

## 数据源安装 $ yum -y install wget $ wget http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm $ yum localinstall mysql57-community-release-el7-8.noarch.rpm $ yum repolist enabled | grep "mysql.*-community.*" $ yum install mysql-…...

DNS解析

1.DNS介绍 DNS 表示域名系统。此系统实质上是用于整理和识别各个域名的网络电话簿。电话簿将“Acme Pizza”之类的名称转换为要拨打的正确电话号码&#xff0c;而 DNS 将“www.google.com”之类的网络地址转换为托管该网站的计算机的物理 IP 地址&#xff0c;如“74.125.19.147…...

从jdk8 升级到jdk17的问题总结

目录 1. java.lang.reflect.InaccessibleObjectException: 2. java.lang.UnsatisfiedLinkError in autosys 3. java.lang.NoClassDefFoundError: Could not initialize class net.sf.jasperreports.engine.util.JRStyledTextParser 4. java.lang.UnsatisfiedLinkError: **…...

一百七十二、Flume——Flume采集Kafka数据写入HDFS中(亲测有效、附截图)

一、目的 作为日志采集工具Flume&#xff0c;它在项目中最常见的就是采集Kafka中的数据然后写入HDFS或者HBase中&#xff0c;这里就是用flume采集Kafka的数据导入HDFS中 二、各工具版本 &#xff08;一&#xff09;Kafka kafka_2.13-3.0.0.tgz &#xff08;二&#xff09;…...

pnpm 升级

1. 在以下路径下删除pnpm包 2. 执行which pnpm&#xff0c;在结果目录中删除pnpm 3. sudo npm install -g pnpm 重新安装&#xff0c;node默认使用16...

有关使用HttpServletRequest的Cookie的设置和获取

文章目录 小结问题和解决参考 小结 介绍了如何在HttpServletRequest中对Cookie的进行设置和获取。 问题和解决 在服务器端的HttpServletRequest中对Cookie的进行设置后&#xff0c;客户端在接下来的请求中会携带此设置好的Cookie&#xff0c;所以可以在服务器端接收请求时提…...

网站建设要学哪些软件/好推建站

转载&#xff1a;原型模式 - C语言中文网 原型&#xff08;Prototype&#xff09;模式的定义如下&#xff1a;用一个已经创建的实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型相同或相似的新对象。 引入原型模式的本质在于利用已有的一个原型对象&#xff0c; …...

网站建设招代理/上海sem

three.js 是一款WebGL框架&#xff0c;WebGL可以让我们在canvas上实现3D效果。实现3D效果在国内来说还算是比较新的东西&#xff0c;可供查阅的资料也不多。这篇文章仅是一个入门篇&#xff0c;介绍如何绘制一个3D正方体。介绍完毕&#xff0c;首先奉上实现的效果图&#xff1a…...

网站不用备案/自媒体账号申请

1、窗口全屏的两种方法&#xff1a;转自&#xff1a;http://blog.sina.com.cn/s/blog_4c451e0e010133ab.html设置全屏包括两个部分&#xff1a; 窗口全屏和Activity全屏。窗口全屏是指隐藏系统顶部用来显示时间、电量、信号等信息的标题栏&#xff1b;Activity全屏是指隐藏程序…...

朔州建设机械网站/中国新闻发布

如何解决动态数据表名&#xff0c;动态字段名情况下&#xff0c;由 ibatis 缓存 select 字段而引起的 字段找不到的情况&#xff1f;以下是最简单的解决办法&#xff01; 当使用动态表&#xff0c;动态字段时&#xff0c;会引起字段名的缓存&#xff0c;以下是解决办法。 先看一…...

最有效的网站推广设计/seo网站优化怎么做

make报错1、undefined reference to symbol *** DSO missing ***2、对***未定义的引用make报错&#xff0c;解决方案添加-l指定库文件。下面两种现象&#xff0c;可以通过下面解决方案解决问题&#xff1a; make 报错 1、undefined reference to symbol *** DSO missing *** …...

网站做弹幕广告/国外免费域名

阅读本文需要 2 分钟。 夏天天气非常热的时候整晚吹空调经常会吹得整个人都不舒服&#xff0c;早上起来很疲惫&#xff0c;达不到轻松睡眠的效果。空调吹久了还是会感觉到冷&#xff0c;定时功能不能完全满足需求&#xff0c;半夜醒来开了关&#xff0c;关了开实在是太折磨人了…...