读写锁分离的循环队列

简介: 在很多需要高性能的场合下,锁的设计一直是一个比较关键的问题。无锁队列、读写锁分离的队列在业界以及学术界都已经有很成熟的研究。在网上也有很多资料,但其实有很多实现都是错误的。最近在工作中帮忙追查一个线上问题时,就发现实现一个正确的版本是比较困难的事情。

在很多需要高性能的场合下,锁的设计一直是一个比较关键的问题。无锁队列、读写锁分离的队列在业界以及学术界都已经有很成熟的研究。在网上也有很多资料,但其实有很多实现都是错误的。最近在工作中帮忙追查一个线上问题时,就发现实现一个正确的版本是比较困难的事情。 

      背景:实现一个循环队列,队列长度已预先分配。支持不同线程的多写多读。

      原本的实现是对读和写分别使用了两个不同的锁来提升性能,但是在最早实现的时候并没有发现到线程间数据的同步修改会造成小概率读取脏数据导致线上服务有问题

复制代码
 1 size_t Queue::pop(int &value)
2 {
3 AutoLock lock(_poplock);
4 if (!empty()) {
5 value = _queue[_read];
6 ++ _read;
7 if (_read == _maxsize) {
8 _read = 0;
9 }
10 return 1;
11 }
12 return 0;
13 }
14
15 size_t Queue::push(int value)
16 {
17 AutoLock lock(_pushlock);
18 if (!full()) {
19 _queue[_write] = value;
20 ++ _write;
21 if (_write == _maxsize) {
22 _write = 0;
23 }
24 return 1;
25 }
26 return 0;
27 }
复制代码

      出现的问题原因是 _read 和 _write 是存在非法的状态(_read = _max_size)。考虑这种场景当_read = _write=_max_size-1时,如果一个线程执行了push操作,并停在if (_write == _maxsize).但是由于线程间的切换,有两个线程继续执行了pop操作,那么就存在一个线程取到了脏数据。

      修改的方法可以两种:1 将读写锁合并成一个锁,但是会降低性能 2 修改实现,使 _read 和 _write不存在非法状态

View Code

 

目录
相关文章
|
8月前
|
算法 调度 C++
【C/C++ 数据结构 线性表】C/C++中队列的原理与实现:从基础到循环队列
【C/C++ 数据结构 线性表】C/C++中队列的原理与实现:从基础到循环队列
177 0
|
存储
栈和队列(二) 队列操作详解及栈与队列的相互实现
栈和队列(二) 队列操作详解及栈与队列的相互实现
96 0
|
3月前
|
运维 API 计算机视觉
深度解密协程锁、信号量以及线程锁的实现原理
深度解密协程锁、信号量以及线程锁的实现原理
55 2
|
7月前
|
安全 调度 C++
互斥锁 vs 自旋锁:底层机制详细解析
互斥锁 vs 自旋锁:底层机制详细解析
170 1
|
API 调度 C语言
互斥锁,自旋锁,原子操作的原理,区别和实现
v互斥锁,自旋锁,原子操作的原理,区别和实现
156 0
|
8月前
|
缓存 算法 Java
为什么需要无锁队列
为什么需要无锁队列
92 0
生产者消费者模型(基于标准库提供的阻塞队列、基于环形数组自实现的阻塞队列)
生产者消费者模型(基于标准库提供的阻塞队列、基于环形数组自实现的阻塞队列)
|
缓存 算法 安全
环形数组无锁队列的原理与实现
环形数组无锁队列的原理与实现
216 0
|
Java 程序员 API
AQS抽象队列同步器
AQS抽象队列同步器
AQS抽象队列同步器
|
前端开发 JavaScript 算法
【化解数据结构】详解队列,优先队列,循环队列,并实现一个队列
【化解数据结构】详解队列,优先队列,循环队列,并实现一个队列
186 0
【化解数据结构】详解队列,优先队列,循环队列,并实现一个队列