循环队列和阻塞有什么关系?和生产者消费者模型又有什么关系?阻塞队列和异步日志又有什么关系
### 循环队列和阻塞队列
#### 循环队列
- **定义**: 一个固定大小的数组,通过两个指针(`front` 和 `back`)管理队列的头部和尾部元素。
- **特点**:
- **循环性**: 当指针到达数组的末尾时,可以回绕到数组的开头,从而利用数组的全部空间。
- **空间效率**: 使用固定大小的数组,避免了动态内存分配和释放带来的开销。
#### 阻塞队列
- **定义**: 一种线程安全的队列,在队列为空时尝试出队的线程会被阻塞,在队列已满时尝试入队的线程也会被阻塞。
- **特点**:
- **线程安全**: 使用互斥锁和条件变量来保证多线程环境下的安全访问。
- **阻塞机制**: 当队列为空或已满时,通过条件变量阻塞相应的线程,直到队列状态发生改变。
### 阻塞队列与生产者-消费者模型
#### 生产者-消费者模型
- **定义**: 一种经典的多线程同步模型,通常涉及两个角色:生产者和消费者。
- **生产者**: 负责生产数据并将其放入队列。
- **消费者**: 负责从队列中取出数据进行处理。
- **特点**:
- **解耦**: 生产者和消费者通过共享队列进行数据交换,彼此之间解耦。
- **同步**: 使用阻塞队列来实现生产者和消费者之间的同步。
### 阻塞队列与异步日志系统
#### 异步日志系统
- **定义**: 一种日志记录系统,其中日志记录操作与业务逻辑操作分离,通过异步机制提高性能。
- **特点**:
- **非阻塞**: 业务逻辑线程将日志消息放入队列后立即返回,而不是等待日志写入完成。
- **后台处理**: 专门的日志线程从队列中取出日志消息并写入日志文件。
#### 阻塞队列在异步日志系统中的应用
- **队列**: 用于存放日志消息。
- **生产者**: 业务逻辑线程,将日志消息放入队列。
- **消费者**: 日志处理线程,从队列中取出日志消息并写入日志文件。
- **同步**: 通过阻塞队列实现生产者和消费者的同步,确保日志消息不会丢失且处理有序。
### 代码分析
- **构造函数**: 初始化队列的最大大小和内部数组。
- **析构函数**: 销毁队列,释放内存。
- **清空队列**: 清空队列内容并重置指针。
- **检查队列状态**: 判断队列是否为空或已满。
- **获取队首和队尾元素**: 安全地获取队列的首尾元素。
- **入队和出队操作**: 提供线程安全的入队和出队操作,使用条件变量实现阻塞机制。
总的来说,这个阻塞队列通过互斥锁和条件变量,实现了多线程环境下的安全访问和同步机制,可以用于生产者-消费者模型中,实现高效的异步日志系统。
#ifndef BLOCK_QUEUE_H
#define BLOCK_QUEUE_H
#include<iostream>
#include<stdio.h>
#include<pthread.h>
#include<sys/time.h>
#include"../lock/locker.h"
using namespace std;
template<class T>
class block_queue{
public:
/*初始化阻塞队列*/
block_queue(int max_size) {
if (max_size <= 0) {
exit(-1);
}
m_max_size = max_size;
T* m_array = new T[max_size];
m_size = 0;
m_front = -1;
m_back = -1;
}
/*删除new出的T数组*/
~block_queue() {
m_mutex.lock();
if (m_array != NULL) {
delete []m_array;
}
m_mutex.unlock();
}
/*清空队列*/
void clear() {
m_mutex.lock();
m_size = 0;
m_front = -1;
m_back = -1;
m_mutex.unlock();
}
/*判断队列是否已满*/
bool full() {
m_mutex.lock();
if (m_size >= m_max_size) {
m_mutex.unlock();
return true;
}
m_mutex.unlock();
return false;
}
/*判断队列是否为空*/
bool empty() {
m_mutex.lock();
if (m_size == 0) {
m_mutex.unlock();
return true;
}
m_mutex.unlock();
return false;
}
/*获得队首元素*/
bool front(T &value) {
m_mutex.lock();
/*注意下面的if判断不能用empty,因为empty函数也有加锁操作,加两次锁会导致死锁*/
if (size == 0) {
m_mutex.unlock();
return false;
}
//TODO:个人感觉这行逻辑出错,后面部分是原代码 value = m_array[m_front];
value = m_array[(m_front + 1) % m_max_size];
m_mutex.unlock();
return true;
}
/*获得队尾元素*/
bool back(T& value) {
m_mutex.lock();
if (size == 0) {
m_mutex.unlock();
return false;
}
value = m_array[m_back];
m_mutex.unlock();
return true;
}
int size() {
int tmp = 0;
m_mutex.lock();
tmp = m_size;
m_mutex.unlock();
return tmp;
}
int max_size() {
int tmp = 0;
m_mutex.lock();
tmp = m_max_size;
m_mutex.unlock();
return tmp;
}
/*往队列中添加元素前需要先将所有使用队列的线程先唤醒*/
/*阻塞队列封装了生产者消费者模型,调用push的是生产者,也就是工作线程*/
bool push(T& item) {
m_mutex.lock();
if (m_size >= m_max_size) {
cond.broadcast();
m_mutex.unlock();
return false;
}
m_back = (m_back + 1) % m_max_size;
m_array[m_back] = item;
m_size++;
cond.broadcast();
m_mutex.unlock();
return true;
}
/*调用pop的是消费者,负责把生产者的内容写入文件*/
bool pop(T& item) {
m_mutex.lock();
while (m_size <= 0) {
if (!cond.wait(m_mutex.get())) {
m_mutex.unlock();
return false;
}
}
m_front = (m_front + 1) % m_max_size;
item = m_array[m_front];
m_size--;
m_mutex.unlock();
return true;
}
bool pop(T& item,int ms_timeout) {
struct timespec t = {0,0};//tv_sec :从1970年1月1日 0点到现在的秒数 tv_nsec:tv_sec后面的纳秒数
struct timeval now = {0,0};//tv_sec: 从1970年1月1日 0点到现在的秒数 tu_usec:tv_sec后面的微妙数
gettimeofday(&now,nullptr);
m_mutex.lock();
if (m_size <= 0) {
t.tv_sec = now.tv_sec + ms_timeout/1000;
t.tv_nsec = (ms_timeout % 1000) * 1000;
if (!m_cond.timewait(m_mutex.get(), t)) {
m_mutex.unlock();
return false;
}
}
//TODO:这一块代码的意义不知道在哪里,留着DEBUG
if (m_size <= 0) {
m_mutex.unlock();
return false;
}
m_front = (m_front + 1) % m_max_size;
item = m_array[m_front];
m_size--;
m_mutex.unlock();
return true;
}
private:
locker m_mutex;
cond m_cond;
T* m_array;
int m_max_size;
int m_size;
int m_front;
int m_back;
};
#endif
相关文章:
循环队列和阻塞有什么关系?和生产者消费者模型又有什么关系?阻塞队列和异步日志又有什么关系
### 循环队列和阻塞队列 #### 循环队列 - **定义**: 一个固定大小的数组,通过两个指针(front 和 back)管理队列的头部和尾部元素。 - **特点**: - **循环性**: 当指针到达数组的末尾时,可以回绕到数组的开头,从而利…...
物理笔记-八年级上册
0.梦开始的地方 物理研究什么? 电学,力学,声学,光学,热学。 1.1.1长度的单位 国际基本单位制 单位转换 魔法记忆:千米-米-毫米-微米-纳米(进率都是1000) 单位换算计算方法 用科学…...
QT键盘和鼠标事件
这些事件都在QWidget 中的保护成员方法中 都是虚函数在头文件中声明了 需要类外重现实现 如果头文件中声明 类外无实现就会报错 void Widget::keyPressEvent(QKeyEvent *event) {switch (event->key()) {//获取按键case Qt::Key_W://按键wqDebug()<<"按下w"…...
文件Io编程基础
1. 标准I/O (stdio.h) stdio.h 是标准C库的头文件,包含了输入输出函数的声明。位置:/usr/include/stdio.h 2. 文件I/O操作步骤 打开文件: 使用 fopen 函数,返回 FILE* 指针。读/写操作: 使用 fread、fwrite、fgets、fputs、fprintf、fscan…...
本地项目提交到Gitee
在项目目录 右键 git bash here 可以在黑屏输入命令 也可以在项目里面 命令都是一样的 要排除哪些 git add . 添加所有文件 git commit -m "Initial commit" 提交到本地 git remote add origin https://gitee.com/xxxx/xxxx.git 添加远程仓库 …...
有了谷歌账号在登录游戏或者新APP、新设备时,要求在手机上点击通知和数字,怎么办?
有的朋友可能遇到过,自己注册或购买了谷歌账号以后,在自己的手机上可以正常登录,也完成了相关的设置,看起来一切都很完美,可以愉快地玩耍了。 但是,随后要登录一个游戏的时候(或者登录一个新的…...
rsyslog如何配置日志轮转
以下是在 Linux 系统中配置 rsyslog 日志轮转策略的一般步骤: 编辑 rsyslog 的配置文件,通常为 /etc/rsyslog.conf 或 /etc/rsyslog.d/*.conf 。 在配置文件中添加类似以下的日志轮转配置示例: $template myLogs,"/var/log/mylog-%Y%m%d…...
LLM推理入门实践:基于 Hugging Face Transformers 和 Qwen2模型 进行文本问答
文章目录 1. HuggingFace模型下载2. 模型推理:文本问答 1. HuggingFace模型下载 模型在 HuggingFace 下载,如果下载速度太慢,可以在 HuggingFace镜像网站 或 ModelScope 进行下载。 使用HuggingFace的下载命令(需要先注册Huggin…...
python:YOLO格式数据集图片和标注信息查看器
作者:CSDN _养乐多_ 本文将介绍如何实现一个可视化图片和标签信息的查看器,代码使用python实现。点击下一张和上一张可以切换图片。 文章目录 一、脚本界面二、完整代码 一、脚本界面 界面如下图所示, 二、完整代码 使用代码时࿰…...
AGI思考探究的意义、价值与乐趣 Ⅴ
搞清楚模型对知识或模式的学习与迁移对于泛化意味什么,或者说两者间的本质?相信大家对泛化性作为大语言模型LLM的突出能力已经非常了解了 - 这也是当前LLM体现出令人惊叹的通用与涌现能力的基础前提,这里不再过多赘述,但仍希望大家…...
c++: mangle命名规则
其实可用根据binutils/c++filt的源代码看。找到mangle的命名规则, 但是从网上找到了一个总结,但是github有时候上不去,摘录再次。 https://github.com/gchatelet/gcc_cpp_mangling_documentation https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling 举例: _ZN8…...
系统化学习 H264视频编码(05)码流数据及相关概念解读
说明:我们参考黄金圈学习法(什么是黄金圈法则?->模型 黄金圈法则,本文使用:why-what)来学习音H264视频编码。本系列文章侧重于理解视频编码的知识体系和实践方法,理论方面会更多地讲清楚 音视频中概念的…...
【VMware】如何演示使用U盘在VMware虚拟机上安装Windows11
一、前置准备 在开始使用U盘演示在VMware虚拟机上装Windows11前,我们需要做以下前置的准备: 已制作好的Windows引导盘;WMware软件 如何制作Windows引导盘? 推荐参考: 【建议收藏】2024年最新Windows系统重装教程&…...
HanLP和Jieba区别
HanLP和Jieba都是中文分词工具,但它们在多个方面存在区别。以下是对两者区别的详细分析: 一、开发背景与语言支持 HanLP:由大连理工大学自然语言处理与社会人文计算实验室开发,是一个开源的自然语言处理工具包。它主要使用Java语…...
荒原之梦考研:考研二战会很难吗?
考研二战是不是很难,其实很大程度上取决于我们自己,我们能否认清自己的优势,能否指定和执行合理的计划,有没有强大的心理支撑等,都是决定考研二战能否成功,或者能否比较轻松的成功的关键。 在本文中&#…...
【Git企业级开发实战指南①】Git安装、基本操作!
目录 一、Git是什么?1.1特点1.2功能1.3基本概念 二、Git安装2.1Ubuntu下安装2.2Centos下安装Git 三、Git基本操作3.1创建git本地仓库3.2配置Git3.3 工作区&暂存区&版本库3.4 实操案例3.4.1添加文件 3.5 修改文件3.6版本回退3.7查看历史操作日志3.7撤销修改3…...
Leetcode 3239. Minimum Number of Flips to Make Binary Grid Palindromic I
Leetcode 3239. Minimum Number of Flips to Make Binary Grid Palindromic I 1. 解题思路2. 代码实现 题目链接:3239. Minimum Number of Flips to Make Binary Grid Palindromic I 1. 解题思路 这一题思路上的话就是分别考察一下把所有行都变成回文所需要的fli…...
C++面试基础算法的简要介绍
C是一种广泛使用的编程语言,尤其在算法和数据结构的实现中占据重要地位。以下是对C基础算法的一些介绍,涵盖了排序、查找、搜索算法以及基本的遍历算法等方面。 排序算法 快速排序(Quick Sort) 快速排序是一种分而治之的排序算法…...
【Linux网络编程】套接字Socket(UDP)
网络编程基础概念: ip地址和端口号 ip地址是网络协议地址(4字节32位,形式:xxx.xxx.xxx.xxx xxx在范围[0, 255]内),是IP协议提供的一种统一的地址格式,每台主机的ip地址不同,一个…...
jvm方法返回相关指令ireturn,areturn,return等分析
正文 看图: 做的事情如下: 1:弹出当前的方法栈帧 2:获取上一个方法 3:从当前方法的操作数栈中获取执行结果,并推送到上一个方法的操作数栈中对应的伪代码: Override public void execute(Frame frame) {Thread thread frame.thread();Frame curren…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
