linux--------------------BlockQueue的生产者消费模型

1.基础BlockingQueue的生产者消费模型

1.1 BlockQueue

在多线程编程中阻塞队列是一种常用于实现生产者和消费者模型的数据结构,它与普通的队列区别在于,当队列为空时,从队列获取元素的操作将被阻塞,直到队列中放入了新的数据。当队列满的时候,往里面插入数据也会被阻塞直到有元素被取出

1.2 c++ queue模拟实现阻塞队列的生产消费模型

为了理解我们来看一下代码

#ifndef __BLOCK_QUEUE_HPP__
#define __BLOCK_QUEUE_HPP__
#include <iostream>
#include <string>
#include <queue>
#include <pthread.h>
template <typename T>
class BlockQueue
{
private:
bool IsFull()
{
return _block_queue.size() == _cap;
}
bool IsEmpty()
{
return _block_queue.empty();
}
public:
BlockQueue(int cap) : _cap(cap)
{
_productor_wait_num = 0;
_consumer_wait_num = 0;
pthread_mutex_init(&_mutex, nullptr);
pthread_cond_init(&_product_cond, nullptr);
pthread_cond_init(&_consum_cond, nullptr);
}
void Enqueue(T &in) // ⽣产者⽤的接⼝
{
pthread_mutex_lock(&_mutex);
while(IsFull()) // 保证代码的健壮性
{
// ⽣产线程去等待,是在临界区中休眠的!你现在还持有锁呢!!!
// 1. pthread_cond_wait调⽤是: a. 让调⽤线程等待 b. ⾃动释放曾经持有的
_mutex锁 c. 当条件满⾜,线程唤醒,pthread_cond_wait要求线性
// 必须重新竞争_mutex锁,竞争成功,⽅可返回!!!
// 之前:安全
_productor_wait_num++;
pthread_cond_wait(&_product_cond, &_mutex); // 只要等待,必定会有唤
醒,唤醒的时候,就要继续从这个位置向下运⾏!!
_productor_wait_num--;
// 之后:安全
}
// 进⾏⽣产
// _block_queue.push(std::move(in));
// std::cout << in << std::endl;
_block_queue.push(in);
// 通知消费者来消费
if(_consumer_wait_num > 0)
pthread_cond_signal(&_consum_cond); // pthread_cond_broadcast
pthread_mutex_unlock(&_mutex);
}
void Pop(T *out) // 消费者⽤的接⼝ --- 5个消费者
{
pthread_mutex_lock(&_mutex);
while(IsEmpty()) // 保证代码的健壮性
{
// 消费线程去等待,是在临界区中休眠的!你现在还持有锁呢!!!
// 1. pthread_cond_wait调⽤是: a. 让调⽤进程等待 b. ⾃动释放曾经持有的
_mutex锁
_consumer_wait_num++;
pthread_cond_wait(&_consum_cond, &_mutex); // 伪唤醒
_consumer_wait_num--;
}// 进⾏消费
*out = _block_queue.front();
_block_queue.pop();
// 通知⽣产者来⽣产
if(_productor_wait_num > 0)
pthread_cond_signal(&_product_cond);
pthread_mutex_unlock(&_mutex);
// pthread_cond_signal(&_product_cond);
}
~BlockQueue()
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_product_cond);
pthread_cond_destroy(&_consum_cond);
}
private:
std::queue<T> _block_queue; // 阻塞队列,是被整体使⽤的!!!
int _cap; // 总上限
pthread_mutex_t _mutex; // 保护_block_queue的锁
pthread_cond_t _product_cond; // 专⻔给⽣产者提供的条件变量
pthread_cond_t _consum_cond; // 专⻔给消费者提供的条件变量
int _productor_wait_num;
int _consumer_wait_num;
};📌 注意:这⾥采⽤模版,是想告诉我们,队列中不仅仅可以防⽌内置类型,⽐如int, 对象也可
以作为任务来参与⽣产消费的过程哦.
下⾯附上⼀张代码,⽅便课堂使⽤
#pragma once
#include <iostream>
#include <string>
#include <functional>
// 任务类型1
// class Task
// {
// public:
// Task() {}
// Task(int a, int b) : _a(a), _b(b), _result(0)
// {
// }
// void Excute()
// {
// _result = _a + _b;
// }
// std::string ResultToString()
// {
// return std::to_string(_a) + "+" + std::to_string(_b) + "=" +
std::to_string(_result);
// }
// std::string DebugToString()
// {
// return std::to_string(_a) + "+" + std::to_string(_b) + "=?";
// }
// private:
// int _a;
// int _b;
// int _result;
// };
// 任务类型2
using Task = std::function<void()>;

2-3 为什么ptread_cond_wait需要互斥量

条件等待是线程同步的一种手段,如果只有一个线程,条件不满足,一直等待下去都不会被满足,所以必须要有一个线程通过某些手段,去改变共享变量,使原先的条件不满足变成满足,然后再去友好的通知等待在该条件变量上的线程

条件不会无缘无故的突然变得满足了,必然牵扯到共享数据的变化,所以一定要用互斥锁来保护

按照上⾯的说法,我们设计出如下的代码:先上锁,发现条件不满⾜,解锁,然后等待在条件变
量上不就⾏了,如下代码:
// 错误的设计
pthread_mutex_lock(&mutex);
while (condition_is_false) {
pthread_mutex_unlock(&mutex);
//解锁之后,等待之前,条件可能已经满⾜,信号已经发出,但是该信号可能被错过
pthread_cond_wait(&cond);
pthread_mutex_lock(&mutex);
}
pthread_mutex_unlock(&mutex);

由于解锁和等待不是原子性,调用解锁之后pthread_cond_wait之前,如果有其他的线程获得互斥量摒弃条件满⾜,发送了信号,那么 pthread_cond_wait 将错过这个信 号,可能会导致线程永远阻塞在这个 pthread_cond_wait 。所以解锁和等待必须是⼀个原⼦操作。

2-4 条件变量的使用规范

pthread_mutex_lock(&mutex);
while (条件为假)
pthread_cond_wait(cond, mutex);
修改条件
pthread_mutex_unlock(&mutex);

给条件发现信号

pthread_mutex_lock(&mutex);
设置条件为真
pthread_cond_signal(cond);
pthread_mutex_unlock(&mutex);

2-5条件变量的封装

大家有兴趣的可以看一下

test_4_7_线程池/Cond.h · liu xi peng/linux---ubuntu系统 - 码云 - 开源中国

2-6 POSIX信号量

POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源,但是OIXIS可以用于线程间同步

初始化

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
pshared:0表⽰线程间共享,⾮零表⽰进程间共享
value:信号量初始值

销毁

int sem_destroy(sem_t *sem);

等待

功能:等待信号量,会将信号量的值减1
int sem_wait(sem_t *sem); 
发布
int sem_post(sem_t *sem);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/89605.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89605.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

堆排序算法详解:原理、实现与C语言代码

堆排序&#xff08;Heap Sort&#xff09;是一种高效的排序算法&#xff0c;利用二叉堆数据结构实现。其核心思想是将待排序序列构造成一个大顶堆&#xff08;或小顶堆&#xff09;&#xff0c;通过反复调整堆结构完成排序。下面从原理到实现进行详细解析。一、核心概念&#x…

SSM框架——注入类型

引用类型的注入&#xff1a;Setter方法简单类型的注入&#xff1a;定义简单实例和方法在配置文件中对bean进行配置&#xff0c;使用porperty属性 值用value&#xff08;ref是用来获取bean的&#xff09;构造器方法&#xff1a;构造器方法中需要写name&#xff0c;这样程序就会耦…

信息学奥赛一本通 1552:【例 1】点的距离

【题目链接】 ybt 1552&#xff1a;【例 1】点的距离 【题目考点】 1. 最近公共祖先&#xff08;LCA&#xff09;&#xff1a;倍增求LCA 知识点讲解见&#xff1a;洛谷 P3379 【模板】最近公共祖先&#xff08;LCA&#xff09; 【解题思路】 首先用邻接表保存输入的无权图…

1Panel中的OpenResty使用alias

问题 在服务器上使用了1Panel的OpenResty来管理网站服务&#xff0c;当作是一个Nginx用&#xff0c;想做一个alias来直接管理某个文件夹的文件&#xff0c;于是直接在其中一个网站中使用了alias配置。 location /upload {alias /root/upload;autoindex on;charset utf-8;charse…

小明记账簿焕新记:从单色到多彩的主题进化之路

【从冷静蓝到多彩世界&#xff0c;这一次我们重新定义记账美学】 曾经&#xff0c;打开“小明记账簿”是一片沉稳的蓝色海洋&#xff0c;它像一位理性的财务管家&#xff0c;默默守护着你的每一笔收支。但总有人悄悄问&#xff1a;“能不能多一些颜色&#xff1f;”今天&#x…

Apache IoTDB(1):时序数据库介绍与单机版安装部署指南

目录一、Apache IoTDB 是什么&#xff1f;1.1 产品介绍1.2 产品体系1.3 产品架构二、IoTDB 环境配置2.1 Linux系统需准备环境2.2 Windows系统需准备环境2.3 网络配置2.3.1 关闭防火墙2.3.2 查看端口是否占用2.3.3 避雷经验三、IoTDB 单机版系统部署安装指南3.1 产品下载3.2 注意…

Python 图片爬取入门:从手动下载到自动批量获取

前言 想批量下载网页图片却嫌手动保存太麻烦&#xff1f;本文用 Python 带你实现自动爬取&#xff0c;从分析网站到代码运行&#xff0c;步骤清晰&#xff0c;新手也能快速上手&#xff0c;轻松搞定图片批量获取。 1.安装模块 在开始爬取图片前&#xff0c;我们需要准备好工具…

aspect-ratio: 1 / 1样式在部分手机浏览器中失效的问题怎么解决?

最近在uniapp开发时又遇到了安卓手机不兼容问题&#xff0c;ios系统无影响。开发背景&#xff1a;小编想通过网格布局来实现答题卡的布局&#xff0c;实现五列多行的形式。代码片段&#xff1a;<view class"question-grid"><viewv-for"(question, inde…

RecyclerView与ListView深度对比分析

1. 使用流程对比ListView: 布局XML&#xff1a; 在布局文件中放置 <ListView> 控件&#xff0c;指定 id (如 android:id"id/listView")。数据适配器 (Adapter)&#xff1a; 继承 BaseAdapter 或 ArrayAdapter / CursorAdapter / SimpleAdapter。 重写 getCount…

deepseekAI对接大模型的网页PHP源码带管理后台(可实现上传分析文件)

前端后端都已进行优化&#xff0c;新增可上传文件功能&#xff08;拖拽进去也可以&#xff09;&#xff0c;后端进行风格主题设置&#xff0c;优化数据结构&#xff01;依旧测试网站&#xff1a;iEPMS我的工具箱&#xff0c;你的智慧助手&#xff01;还是那句话兄弟们轻点搞我的…

NJU 凸优化导论(9) 对偶(II)KKT条件+变形重构

https://www.lamda.nju.edu.cn/chengq/optfall24/slides/Lecture_9.pdf 目录 关于对偶的一些解释 1. Max-min characterization 最大最小准则 2. Saddle-point Interpretation 鞍点解释 3. Game interpretation 博弈论里的对偶 Optimality Conditions 最优条件 1. Certi…

Vue Swiper组件

Vue 渐进式JavaScript 框架 基于Vue2的学习笔记 - Vue Swiper组件实现笔记 目录 Swiper组件 下载swiper 创建swiper组件 保存时修复 编写swiper内容 引入swiper 使用swiper Swiper子组件 创建Swiper列表组件 使用子组件 增加生命周期 增加图片显示 加载数据 渲染…

Linux:lvs集群技术

一.集群和分布式1.1 集群集群是为了解决某个特定问题将多台计算机组合起来形成的单个系统。即当单独一台主机无法承载现有的用户请求量&#xff1b;或者一台主机因为单一故障导致业务中断的时候&#xff0c;就可以增加服务主机数&#xff0c;这些主机在一起提供服务&#xff0c…

【管理】持续交付2.0:业务引领的DevOps-精要增订本,读书笔记(理论模型,技术架构,业务价值)

【管理】持续交付2.0&#xff1a;业务引领的DevOps-精要增订本&#xff0c;读书笔记&#xff08;理论模型&#xff0c;技术架构&#xff0c;业务价值&#xff09; 文章目录1、持续交付的理论模型&#xff08;第1-3章&#xff09;1.1 结构图1.2 持续交付的演进1.3 双环模型理论体…

Wilcox检验的星星怎么规定的?

在 R 里&#xff0c;常见的把 p 值映射为“星号”标记&#xff08;显著性水平&#xff09;的规则通常是&#xff1a;p 值范围标记p ≤ 0.0001“****”0.0001 < p ≤ 0.001“***”0.001 < p ≤ 0.01“**”0.01 < p ≤ 0.05“*”0.05 < p ≤ 0.1“.”p > 0.1…

https与DNS的运行流程

HTTPS流程&#xff1a;HTTPS核心:加了TLS层&#xff0c;加密传输身份认证TLS:信息加密、校验机制、身份证书TLS&#xff08;Transport Layer Security&#xff09;握手是建立安全通信通道的关键过程&#xff0c;发生在客户端&#xff08;如浏览器&#xff09;和服务器之间。其主…

板子 5.29--7.19

板子 5.29–7.19 目录 1. 树状数组 2. KMP 3. 矩阵快速幂 4. 数位DP 5. 状压枚举子集 6. 快速幂&#xff08;新版 7. priority_queue 8. dijkstra 9. 单调栈 10. debug内容 1. 树状数组 // 树状数组 快速求前缀和 / 前缀最大值 // 维护位置数量(离散化)...// (区间加 区间求和…

min-max容斥学习笔记

最近报了航电的春季赛&#xff0c;在一道题目里面遇到了做法&#xff0c;感觉挺有意思。 考虑一个&#xff08;多重&#xff09;集合S{ai}S\{a_i\}S{ai​}&#xff0c;有如下的等式成立 min⁡ai∈S(ai)∑T⊆S,T≠∅(−1)∣T∣−1max⁡ai∈T(ai)\min_{a_i\in S}(a_i)\sum_{T\sub…

使用帆软制作项目

https://zhuanlan.zhihu.com/p/23429318335 项目背景 为加快大数据体系建设&#xff0c;稳步推进数字化转型战略&#xff0c;规范数据架构体系和数据治理体系&#xff0c;运用大数据推进全行数字化转型建设&#xff0c;为业务发展提供创新动力&#xff0c;目标是利用金融科技和…

论C/C++的条件编译#if、#ifdef、#ifndef、#undef

我们以实例来演示&#xff1a; ------------------------------------------实验①------------------------------------------ 子函数&#xff1a;主函数&#xff1a;当定义了COMMENT_FLAG该宏&#xff0c;且其为0&#xff0c;则运行结果如下&#xff1a;只执行了sub_func_1函…