FIFO缓存区原理

1.缓存区的制作

思路:按照输入数据的顺序输出数据

简单地数据存储:

struct FIFO_BUF{
          unsigned char data[32];
          int next;
}fifo_buf;

unsigned char buffer[32]={0};

void init_write_to_buf(void)
{
         if(fifo_buf.next<32)
        {
                fifo_buf.data[fifo_buf.next]=buffer[fifo_buf.next];   //将buffer中的数据写入到fifo_buf中;
                fifo_buf.next++;
        }
        return 0;
}

fifo_buf.next的起始点是0,所以最初存储的数据是fifo_buf.data[0],下一个是fifo_buf.data[1],依次类推,一共32个存储位置。

下一个存储位置有用变量next管理,这样就可以记住32数据而不溢出,为保险next变为32之后就不要了

简单地数据读取:

void read_from_fifo_buf(void)
{
        for(;;)
       {
               if(fifo_buf.next==0)
                       return;      //为0表示没有数据,不用读取
              else
              {
                       i = fifo_buf.data[0];   //读取第0个位置的元素;
                       fifo_buf.next--;
                      for(int j=0;j<fifo_buf.next;j++)
                      {
                              fifo_buf.data[j] = fifo_buf.data[j+1];
                      }
              }
       }
}

如果next不是0,说明至少有一个数据,最开始的一个数据肯定放在data[0]中,将这个数据放入到变量i中,这样数据就减少了一个,所以next要减去1;

接下来的for语句工作原理如下:

数据存放的位置全部都向前移动了一个位置。如果不移送的话,下次就不能从data[0]读入数据了。

此方法的缺点:移送数据的处理,一般不会超过3个,且基本上没问题。有时需要移送上百个数据,就会出现问题。

2 改善上述缓存区

思路:不仅要维护下一个要写入数据的位置,还要维护下一个要读出数据的位置。这就好像数据读出位置追着数据写入位置跑一样。这样就不需要数据移送操作了。数据读出位置追上数据写入位置的时候,就相当于缓存区为空,没有数据。

但是这样的缓存区使用一段时间后,下一个数据写入位置会变为31,而这时下一个数据读出位置可能已经是29或者30了。当下一个写入位置变为32的时候,就没地方可以写入数据了。

如果当下一个数据写入位置到达缓存区终点时,数据读出位置也恰好到达缓冲区终点,也就是缓冲区正好变为空,这种情况我们只要将下一个数据写入位置和下一个数据读出位置都再置位0就行了,就像转回去从头再来一样。

但是总还是会有数据读出位置没有追上数据写入位置的情况。这时又不得不进行数据移送操作。

3 缓存区的实现

当下一个数据写入位置到达缓冲区最末尾时,缓存区开头部分应该已经变空了(如果还没有变空,说明数据读出跟不上数据写入,只能把部分数据扔掉了)。因此如果下一个数据写入位置到了32以后,就强制性的将它设置为0。这样写一个数据写入位置就跑到了下一个数据读出位置的后面。

对下一个数据读出位置也做同样的处理。一旦到了32以后,就把它设置为从0开始继续读取数据。这样32字节的缓存区就能一圈一圈地不停循环,长久使用。数据移送操作一次都不需要。这个缓存区虽然只有32字节,只要不溢出的话,他就能持续使用下去。

数据的写入

struct FIFO_BUF{
        unsigned char data[32];
        int next_w;       //写位置标志
        int next_r;        //读位置标志
        int len;             //数据长度
}fifo_buf;
void write_to_fifo_buf(void)
{
        if(fifo_buf.len>=32)
                return;
        else
       {
               fifo_buf.data = data;     //将一个数据写入到缓存中
               fifo_buf.next_w++;
               fifo_buf.len++;
               if(fifo_buf.next_w==32)
                     fifo_buf.next=0;
       }
       return 0;
}

数据的读取

void read_from_fifo_buf(void)
{
        for(;;)
       {
               i = fifo_buf.data[fifo_buf.next_r];   //读取next_r处的数据
              fifo_buf.len--;
              fifo_buf.next_r++;
              if(fifo_buf.next_r==32)
              {
                      fifo_buf.next_r=0;
              }
       }
}

4 FIFO缓存区最终实现

struct FIFO_BUF
{
        unsigned char *buf;
        int fifo_w;
        int fifo_r;
        int len;     //缓存区总的字节数
        int free;    //用于保存缓存区里没有数据的字节数
        int flags;
}fifo_buf;

初始化

void fifo_init(fifo_buf *fifo,int len,unsigned char *buf)
{
        fifo->buf = buf;
        fifo->len = len;
        fifo->free = len;
        fifo->fifo_w = 0;
        fifo->fifo_r = 0;
        fifo->flags = 0;
        return;
}

#define FLAGS_OVERRUN 0x0001

int fifo_write(struct fifo_buf *fifo,unsigned char data)
{
        if(fifo->free == 0) //空余没有了,溢出
        {
                fifo->flags |= FLAGS_OVERRUN;
                return -1;
        }
        fifo->buf[fifo->fifo_w]=data;
        fifo->fifo_w++;
        if(fifo->w==fifo->len)
       {
               fifo->w = 0;
       }
       fifo->free--;
       return 0;
}

int fifo_read(fifo_buf *fifo,unsigned char buffer)
{
        if(fifo->free == fifo->len)
        {
                return -1;
        }
       else
       {
                buffer = fifo->buf[fifo->fifo_r];    //一个数据写入到buffer中
                fifo->fifo_r++;
                if(fifo->fifo_r==32)
                {
                        fifo->fifo_r = 0;
                }
                fifo->free++;
       }
       return buffer;
}

查询写入了多少数据

int fifo_status(void)
{
        return fifo->len - fifo->free;
}

原文地址:https://www.cnblogs.com/dongry/p/11144358.html

时间: 2024-11-02 10:10:16

FIFO缓存区原理的相关文章

单字节的FIFO缓存(30天自制操作系统--读书笔记)

从今天起,写一些读书笔记.最近几个月都在看<30天自制操作系统这本书>,书虽说看的是电子书,但可以花钱买的正版书,既然花费了金钱,就总得有些收获. 任何人都不能总是固步自封,想要进步就得学习别人的知识,对于程序员而言,最简单的方法即是学习别人的代码. 今天的标题是“单字节的FIFO缓存”,其实就是做一个FIFO,看名字就知道了.也就4个函数和1个相关结构体,这样的小代码在嵌入式系统中很常用,也会很好用. 1.相关数据结构体 struct FIFO8 { unsigned char *buf;

基于LinkedHashMap实现LRU缓存调度算法原理

引言 本文就 <基于LinkedHashMap实现LRU缓存调度算法原理及应用 >一文作为材料,记录一些常见问题,备忘. 延伸出两道常见的Java面试题: 插入Entry节点到table表的链表中时,Hashmap 和LinkedHashmap使用头茶法还是尾茶法?遍历map的时候,Entry.Entryset()获取的set集合,是按照从头到尾还是从尾到头的顺序存储的? 实现LRU算法最合适的数据结构? 如果读者可以打出来,不用继续看下边的资料了.初学者请继续阅读.相信你读完之后可以找到问题

LRU、FIFO缓存实现以及LinkedHashMap源码

本篇将描述如何使用LinkedHashMap实现LRU以及FIFO缓存,并将从LinkedHashMap源码层面描述是如何实现这两种缓存的. 1.缓存描述 首先介绍一下FIFO.LRU两种缓存: FIFO(First In First out):先见先出,淘汰最先近来的页面,新进来的页面最迟被淘汰,完全符合队列. LRU(Least recently used):最近最少使用,淘汰最近不使用的页面. 2.代码实现 以下是通过LinkedHashMap实现两种缓存. public class Ca

IntelliJ IDEA修改Output输出缓存区大小【应对:too much output to process】

IntelliJ IDEA默认的Output输出缓存区大小只有1024KB,超过大小限制的就会被清除,而且还会显示[too much output to process],可通过如下配置界面进行修改(Settings→Editor→Console),单位为KB 如果需要禁用缓存区大小限制就需要修改配置文件idea.properties 配置文件中原有设置: #---------------------------------------------------------------------

ACM/ICPC 之 优先级队列+设置IO缓存区(TSH OJ-Schedule(任务调度))

一个裸的优先级队列(最大堆)题,但也有其他普通队列的做法.这道题我做了两天,结果发现是输入输出太过频繁,一直只能A掉55%的数据,其他都是TLE,如果将输入输出的数据放入缓存区,然后满区输出,可以将IO时间消耗降到很低. 任务调度(Schedule) 描述 某高性能计算集群(HPC cluster)采用的任务调度器与众不同.为简化起见,假定该集群不支持多任务同时执行,故同一时刻只有单个任务处于执行状态.初始状态下,每个任务都由称作优先级数的一个整数指定优先级,该数值越小优先级越高:若优先级数相等

调优5(SGA其他缓存区调整)

第五章 SGA其他缓存区调整 一.redo log buffer 1.redo log 的功能1)Sever 进程在buffer cache修改数据块后,Oracle提倡'先记后写',对修改的数据块的改变生成log entries(日志条目),将日志条目按顺序写入log buffer:而对于脏块 先链接到检查点队列,等待dbwr 进程写入到datafile2) 进程会及时的将其按顺序写入到redo log files.(日志条目的数据块大小一般和操作系统数据块大小一致,在Unix 和linux

JAVA之旅(十七)——StringBuffer的概述,存储,删除,获取,修改,反转,将缓存区的数据存储到数组中,StringBuilder

JAVA之旅(十七)--StringBuffer的概述,存储,删除,获取,修改,反转,将缓存区的数据存储到数组中,StringBuilder 讲完String,我们来聊聊他的小兄弟 一.StringBuffer概述 关于StringBuffer这个对象,Buffer是什么意思?缓冲区的意思,String一旦初始化时不可以被改变的,而StringBuffer是可以的,这就是区别,特点: StringBuffer是一个容器 可以字节操作多个数据类型 最终会通过toString方法变成字符串 存储 S

git --如何撤销已放入缓存区(Index区)的修改

修改或新增的文件通过 git add --all 命令全部加入缓存区(index区)之后,使用 git status 查看状态(git status -s 简单模式查看状态,第一列本地库和缓存区的差异,第二列缓存区和工作目录的差异),提示使用 git reset HEAD <file> 来取消缓存区的修改. 不添加<file>参数,撤销所有缓存区的修改. 另外可以使用 git rm --cached 文件名 ,可以从缓存区移除文件,使该文件变为未跟踪的状态,同时下次提交时从本地库中

缓存区溢出攻击实验(3)

缓存区溢出攻击实验(3) 本实验预计分 3 个小实验来做,本文是第三个实验. 缓存区溢出攻击实验(1) 缓存区溢出攻击实验(2) 缓存区溢出攻击实验(3) 本实验跪谢大神 YSunLIN 的帮助与指导 ~ 不保证成功,一切皆有可能 ~ 背景介绍 请参照实验(1)(2). 实验目的 最终目的:只给一个需要输入正确的序列号才能验证通过的exe可执行文件,要求在不知道源代码的情况下利用缓存区溢出攻击来破解该exe文件. 注意!!! 不知道源代码的情况下 不知道源代码的情况下 不知道源代码的情况下 现实