环形缓冲区

来源:互联网 发布:java职业培训 编辑:程序博客网 时间:2024/04/28 05:54

1、什么是环形缓冲区

  • 环形缓冲区,顾名思义就是一个环状的存储数据的区域,其空间使用数组进行构造(链表也可以)。环形缓冲区特点是读和写可以是分开的,写入数据之后可以先不去读取,等到需要读取的时候再去读取,并且数据一经读取之后下次就不能再去读取(当然也可以实现重复读取的效果,不过大多用作一次性读取),等于说是一次性的读取。
  • 假设一个长度为256字节的数组,构建出一个环形缓冲区,当写操作进行到数组的第256项之后,再一次写入就会回到第0个进行写入;同样读操作是读取到数组的第256项时,再一次进行读取就会回到数组的第一项。是谓环形缓冲

2、环形缓冲区的作用

用作需要大量写入并且大量一次性读写的数据缓存区

比如视频的写入读取:在视频播放的时候需要不断的进行写入读取操作,而且数据一经读出就会显示出来,下次就不再需要已经读出的数据了。使用环形缓冲区可以满足这个要求,并且实现读写分别进行,而且节省了空间。

用作进程间通信,减少加锁开销

由于环形缓冲区的读写分开特性,当两个线程进行通信的时候,可以采用环形缓冲区进行交流,一个进程读取,一个进程写入,由于读写的位置不同,并不需要加锁进行并发控制,也就减少了锁的时间开销

3、程序编写测试(基于嵌入式linux的kmesg方式建立)

/* 使用printk函数打印调试信息,调试信息写到proc里面,形成一个环形缓冲区 */#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <asm/uaccess.h>/* proc的文件结构体 */struct proc_dir_entry *entry;#define MAX_COUNT 1024  //缓冲区长度static char proc_buffer[MAX_COUNT]; //缓冲区数组static int empty_flag = 0;  //是否为空,0表示为空static int last_r_pos = 0;static int mymsg_r = 0; //读位置static int mymsg_w = 0; //写位置/* 判断是否为空 */static int is_empty_mymsg(void){    if(((mymsg_w % MAX_COUNT)  == (mymsg_r % MAX_COUNT)) && (empty_flag == 0)){        return 1;   //Is empty    }    return 0;   //Is not empty}/* 判断是否为满 */static int is_full_mymsg(void){    if(((mymsg_w % MAX_COUNT) == (mymsg_r % MAX_COUNT)) && (empty_flag != 0)){        return 1;   //Is full    }    return 0;   //Is not full}/* 读取一个字节 */static int read_onebyte_mymsg(char *buf_p){    if(is_empty_mymsg()){        return 0;   //empty buffer can't read    }    *buf_p = proc_buffer[mymsg_r % MAX_COUNT];    mymsg_r = (mymsg_r + 1) % MAX_COUNT;    empty_flag --;  //每读取一个字节空标志减去1    return 1;}/* 写入一个字节 */static void write_onebyte_mymsg(char byte){    proc_buffer[mymsg_w % MAX_COUNT] = byte;    if(is_full_mymsg()){        mymsg_r = (mymsg_r + 1) % MAX_COUNT;        empty_flag --;    }    mymsg_w = (mymsg_w + 1) % MAX_COUNT;    empty_flag ++;  //每写入一个字节,空标志加一}/* 执行cat命令的时候会调用到,直到返回为空的时候cat才会返回 */static ssize_t printk_drv_read(struct file *f_name, char __user *buf, size_t cont, loff_t *lof){    char byte_to_user;    cont = read_onebyte_mymsg(&byte_to_user);    __put_user(byte_to_user, buf);    return cont;}/* 自建打印函数,另带有往环形缓冲区里面写入数据的功能 */int myprintk(const char *fmt, ...){    va_list args;    int r;    va_start(args, fmt);    r = vprintk(fmt, args);    va_end(args);    while(r --){        write_onebyte_mymsg(*fmt++);    }    return r;}EXPORT_SYMBOL(myprintk);const struct file_operations proc_mymsg_operations = {    .owner = THIS_MODULE,    .read = printk_drv_read,};static int printk_drv_init(void){       int i = 0;    /* 打印测试 */    for(i = 0; i < MAX_COUNT; i++){        myprintk("F");    }    /* 边界测试 */    for(i = 0; i < 5; i++){        myprintk("Y");    }//  myprintk("Function printk_drv_init is running\n");    entry = create_proc_entry("mymsg", S_IRUSR, &proc_root);    if (entry)        entry->proc_fops = &proc_mymsg_operations;//  myprintk("Function printk_drv_init finished\n");    return 0;}static void printk_drv_exit(void){    remove_proc_entry("mymsg", &proc_root);}module_init(printk_drv_init);module_exit(printk_drv_exit);MODULE_LICENSE("GPL");

4、测试结果

insmod myprintk.koFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFYYYYYcat /proc/mymsg FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFYYYYY//开始的5个F被清除掉了cat /proc/mymsg空

5、判断环形缓冲区的空或者满

设置额外的标志位

例如上面例子中的empty_flag,写的时候加上1,读的时候减去1,当满足读等于写并且empty_flag为0,则说明缓冲区空了。如果满足读等于写并且empty_flag不为0,说明缓冲区满了。

环形缓冲区始终空出一个值

例如:

/* 判断是否为空 */static int is_empty_mymsg(void){    //if(((mymsg_w % MAX_COUNT)  == (mymsg_r % MAX_COUNT)) && (empty_flag == 0)){    if(((mymsg_w % MAX_COUNT)  == (mymsg_r % MAX_COUNT))){        return 1;   //Is empty    }    return 0;   //Is not empty}/* 判断是否为满 */static int is_full_mymsg(void){    //if(((mymsg_w % MAX_COUNT) == (mymsg_r % MAX_COUNT)) && (empty_flag != 0)){    if((((mymsg_w + 1) % MAX_COUNT) == (mymsg_r % MAX_COUNT))){        return 1;   //Is full    }    return 0;   //Is not full}

这样就会导致在read位置前面的一个字节始终不能够写入数据,但是却很轻易的区分出来缓冲区是满还是空

0 0
原创粉丝点击