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

C++并发编程:构建线程安全队列(第二部分:细粒度锁)

C++并发编程:构建线程安全队列(第二部分:细粒度锁)

1. 引言

在多线程环境下,为了保证数据的一致性和正确性,需要使用同步原语来对共享数据的访问进行互斥和同步。std::queue作为一种先进先出(FIFO)的数据结构,它本身并不是线程安全的,同时访问它可能导致数据竞争和不一致的问题。

所以在多线程环境下,我们需要构建一个线程安全的队列,使其可以安全地被多个线程同时访问,而不会出现数据竞争。这里我们使用C++11中的一些新特性如std::shared_ptrstd::unique_ptrstd::mutexstd::condition_variable等来实现一个线程安全队列。

2. 设计要点

线程安全队列的关键设计要点包括:

  • 使用互斥量保护队列的头尾指针,使多线程不能同时修改队列结构
  • 使用条件变量实现线程之间的通知和等待,避免忙等待(busy waiting)
  • 提供多种不同的访问接口如阻塞、非阻塞、等待获取等,增强队列的实用性
  • 使用std::shared_ptrstd::unique_ptr等智能指针管理内存,避免手动new/delete带来的问题
  • 尽量减少锁的粒度,例如头尾指针使用不同的锁,以提高并发性

下面我们来看一下这个线程安全队列的具体设计和实现。

3. 队列的节点结构

队列节点node使用一个std::shared_ptr保存数据,和一个std::unique_ptr指向下一节点:

struct node
{std::shared_ptr<T> data;std::unique_ptr<node> next;
};

使用shared_ptr而不是原始指针管理数据,可以自动释放内存,避免泄漏。unique_ptr则保证节点间的引用关系唯一,方便传递所有权。

4. 队列结构

队列结构包含头尾指针、互斥量和条件变量:

std::mutex head_mutex;
std::unique_ptr<node> head;std::mutex tail_mutex; 
node* tail;std::condition_variable data_cond;

头指针使用unique_ptr且初始化为一个哑节点。尾指针使用原始指针,初始化指向哑节点。

头尾指针分别使用head_mutextail_mutex保护,以减小锁的粒度,不同指针可以并发修改。

条件变量data_cond用于在队列为空时等待,并在有数据可获取时发出通知。

5. 主要接口

队列主要提供下面一些接口:

5.1 非阻塞获取

try_pop尝试非阻塞地弹出队头元素,如果队列为空则直接返回:

std::shared_ptr<T> try_pop() 
{std::lock_guard<std::mutex> head_lock(head_mutex);if (head.get() == get_tail()) {return {}; }return std::move(head->data);
}

仅对头指针上锁,执行常数时间操作,可并发访问。

5.2 阻塞获取

wait_and_pop会在队列为空时等待,直到有元素入队后唤醒线程并返回数据:

std::shared_ptr<T> wait_and_pop()
{std::unique_lock<std::mutex> head_lock(wait_for_data());return std::move(head->data); 
}std::unique_lock<std::mutex> wait_for_data()
{std::unique_lock<std::mutex> 
http://www.lryc.cn/news/156012.html

相关文章:

  • 浅述C++内存管理——new与malloc的不同
  • 语言基础篇11——函数、函数参数类型、装饰器、生成器
  • linux jar包class热部署 工具 arthas安装及使用
  • Android studio 调整jar包顺序
  • 用Qt写的机器视觉绘图工具
  • Spring Boot 打包,将依赖全部打进去
  • SpringCloud入门实战(十五)分布式事务框架Seata简介
  • MySQL数据库 主从复制与读写分离
  • Qt day2
  • JavaScript - 好玩的打字动画
  • rpm打包
  • 匠心新品:大彩科技超薄7寸WIFI线控器发布,热泵、温控器、智能家电首选!
  • 华为云云服务器评测|使用云耀云服务器L实例部署Portainer工具
  • C++并发编程:构建线程安全队列(第一部分:粗粒度锁)
  • C++设计模式-更新中
  • Hydra工具的使用
  • Pytorch学习:卷积神经网络—nn.Conv2d、nn.MaxPool2d、nn.ReLU、nn.Linear和nn.Dropout
  • 水果库存系统(SSM+Thymeleaf版)
  • 如何在VueJS应用程序中设置Toast通知
  • css让元素保持等比例宽高
  • 骨传导和入耳式哪个危害大一点?入耳式和骨传导哪种好?
  • 介绍OpenCV
  • Android中的view绘制流程,简单理解
  • 商城开发:店铺管理系统应具备哪些功能?
  • 小白学go基础04-命名惯例对标识符进行命名
  • 使用iCloud和Shortcuts实现跨设备同步与自动化数据采集
  • Spring框架-基于STOMP使用Websocket
  • kafka-- 安装kafka manager及简单使用
  • 深圳-海岸城购物中心数据分析
  • vue3 + elementplus Cannot read properties of null (reading ‘isCE‘)