环形缓冲区【转】

本文转载自:http://blog.csdn.net/u013904227/article/details/51168398

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");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132

4、测试结果

insmod myprintk.ko FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFYYYYY cat /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 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

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

转载于:https://www.cnblogs.com/zzb-Dream-90Time/p/7268419.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值