环形队列

在处理网络分包,包未收完整时,必定需要一个缓冲区来缓存数据,ring_buffer是最常用的选择。它是一个比较简单的数据结构,在学《数据结构》时想必大家都实现过,但我前几天就被它教育了一把,write时,一处分支漏了个等号,些许情况下会缓冲区溢出,导致堆栈一些数据被破坏,让我足足花了一整天才找到这个bug,我错误的地方如下:

 1 int
 2 rbuf_write(struct ring_buffer *self,const char *data,int n){
 3     assert(self);
 4     assert(data);
 5     if(n <= 0){
 6         return 0;
 7     }
 8     for(;;){
 9         unsigned int len = rbuf_length(self) + n;
10         if(len >= INT_MAX){
11             return -1;
12         }
13         if(self->cap - rbuf_length(self) -1 < n){
14             rbuf__expand(self);
15         }
16         else{
17                         //少了等号
18             if(self->tail >self->head){
19                 int copy1 = self->cap - self->tail;
20                 if(copy1 > n ){
21                     copy1 = n;
22                 }
23                 memcpy(self->buf + self->tail,data,copy1);
24                 if(copy1 < n){
25                     memcpy(self->buf,data + copy1,n - copy1);
26                 }
27             }
28             else{
29                 memcpy(self->buf + self->tail,data,n);
30             }
31             self->tail = (self->tail + n ) % self->cap;
32             return n;
33         }
34     }
35 }    

第18行的判断应该是>=,否则当n>(self->cap - self->tail)就会溢出。



这里再来回忆一番。我要的接口如下:

1 struct ring_buffer;
2 struct ring_buffer * rbuf_create(int n);
3 void rbuf_destory(struct ring_buffer *);
4 int rbuf_length(struct ring_buffer *);
5 //return 0:length shorter than n, n:success
6 int rbuf_read(struct ring_buffer *self,char *dest,int n);
7 //return -1:length over INT_MAX  n:success
8 int rbuf_write(struct ring_buffer *self,const char *data,int n);

读写时要么读写指定的大小,要么失败。实现它,只需注意如下几点,就不会写错了:

  • 头进尾出,头指向下一个出队的位置,尾指向下一个入队的位置。
  • head == tail时为空队列
  • 队列长度为:(tail - head + cap) % cap
  • 因为头尾相等为空,所以队列可用空间要比容量少1,因次队列满为:队列长度 = cap - 1
  • 头尾的下一位置为:([email protected]+n) % cap
  • 要根据头尾的位置做分段处理

具体实现就放在github上了

时间: 2024-08-08 13:45:47

环形队列的相关文章

Atitit.提升软件稳定性---基于数据库实现的持久化 循环队列 环形队列

Atitit.提升软件稳定性---基于数据库实现的持久化  循环队列 环形队列 1. 前言::选型(马) 1 2. 实现java.util.queue接口 1 3. 当前指针的2个实现方式 1 1.1. 用一个游标last 来指示 (指针表字段last ),麻烦的,不推荐 1 1.2. (简单,推荐)使用循环次数来指示,每循环加1   (字段cirTimes),order by cirtimes 1 4. 表格设计id, cirTimes,createtime,handlerID,recID,d

环形缓冲区的设计及其在生产者消费者模式下的使用(并发有锁环形队列)

1.环形缓冲区 缓冲区的好处,就是空间换时间和协调快慢线程.缓冲区可以用很多设计法,这里说一下环形缓冲区的几种设计方案,可以看成是几种环形缓冲区的模式.设计环形缓冲区涉及到几个点,一是超出缓冲区大小的的索引如何处理,二是如何表示缓冲区满和缓冲区空,三是如何入队.出队,四是缓冲区中数据长度如何计算. ps.规定以下所有方案,在缓冲区满时不可再写入数据,缓冲区空时不能读数据 1.1.常规数组环形缓冲区 设缓冲区大小为N,队头out,队尾in,out.in均是下标表示: 初始时,in=out=0 队头

并发无锁之环形队列生产者消费者问题

1.生产者消费者问题 三种关系:生产者--生产者(互斥):消费者-消费者(互斥):生产者--消费者(互斥同步) 两个角色:生产者:消费者 一种生产场所:缓冲区 2.环形队列(缓冲区) 数据结构:可以有多种,这里选用数组,逻辑上将a[0]和a[size-1]相连构成环形队列 判断空/判断满:当读指针和写指针指向同一个区域为空,或者满(但不能区分空或者满) 两种方案:1.即尾结点与首结点之间至少留有一个元素的空间. 2. 添加一个计数器(信号量就是计数器所以这里用信号量完成计数器的功能) 3.sem

环形队列的实现原理

环形队列是一个首尾相连的FIFO(命名管道)的数据结构,它采用数组的线性空间.它能很快知道队列是否为满或者为空,也能很快的存取数据. 原理: 内存上没有环形结构,因此环形队列利用数组的线性空间来实现.当数据到了尾部时,它将转回到0位置来处理.这个转回操作通过取模来执行. 构造:逻辑上,将数组q[0]与q[MAXN-1]相连接,形成一个存放队列的环形空间. 用数组下标来标明队列的读.写位置.head 指向可以读的位置,tail 指向可以写的位置. 环形队列的关键是判断队列为空或者满.tail 追上

java实现数据结构中的环形队列

最近在看数据结构,队列在数据结构中是个重要的元素. 定义:数据结构是指相互之间存在一种或多种特定关系的数据元素的集合. 队列主要分为普通队列和环形队列,环形队列比普通队列的使用效率更高(普通队列容易造成内存的浪费,时间效率也会降低,主要体现在队列的删除操作上) 下面用java来实现队列,仅供参考 package demo; //环形队列 public class QueueDemo { //创建队列 public QueueDemo(int num){ m_iQueueCapacity=num;

&lt;2014 05 16&gt; 线性表、栈与队列——一个环形队列的C语言实现

栈与队列都是具有特殊存取方式的线性表,栈属于先进后出(FILO),而队列则是先进先出(FIFO).栈能够将递归问题转化为非递归问题,这是它的一个重要特性.除了FILO.FIFO这样的最普遍存取方式外,还有一些扩展的数据结构,如双端队列.双栈.超队列.超栈等,它们是一种扩展与变异结构. 线性表有顺序存储和链接存储两类,这是针对计算机的线性存储空间作出的分类.前者可以是数组,后者可以是链表.字符串是线性表最常见的应用. 这里我用C语言实现了一个基于数组环形队列,它具有固定的队列空间.相比于链表实现,

顺序对列,环形队列,反向链式栈

1.顺序队列 #include<stdio.h> #include <stdlib.h> #define N 100 #define datatype int typedef struct queue { datatype data[N]; int rear;//吃东西 int front;//拉屎 } myQ ,*PmyQ; void init(PmyQ p); int isfull(PmyQ p); int isempty(PmyQ p); void show(PmyQ p);

无锁环形队列

1 #include "stdafx.h" 2 #include <process.h> 3 #include <stdio.h> 4 #include <Windows.h> 5 #include <stdlib.h> 6 #include <assert.h> 7 8 #define MAX_VIDEO_BUFF 1024 9 10 struct Header 11 { 12 WORD wSize; 13 char dat

眉目传情之并发无锁环形队列的实现

眉目传情之并发无锁环形队列的实现 Author:Echo Chen(陈斌) Email:[email protected] Blog:Blog.csdn.net/chen19870707 Date:October 10th, 2014 前面在<眉目传情之匠心独运的kfifo>一文中详细解析了 linux  内核并发无锁环形队列kfifo的原理和实现,kfifo鬼斧神工,博大精深,让人叹为观止,但遗憾的是kfifo为内核提供服务,并未开放出来.剑不试则利钝暗,弓不试则劲挠诬,鹰不试则巧拙惑,马不

数据结构之自建算法库——顺序环形队列

本文针对数据结构基础系列网络课程(3):栈和队列中第9课时环形队列的存储及基本操作. 按照"0207将算法变程序"[视频]部分建议的方法,建设自己的专业基础设施算法库. 顺序环形队列算法库采用程序的多文件组织形式,包括两个文件: 1.头文件:sqqueue.h,包含定义顺序环形队列数据结构的代码.宏定义.要实现算法的函数的声明: #ifndef SQQUEUE_H_INCLUDED #define SQQUEUE_H_INCLUDED #define MaxSize 5 typedef