环形缓冲区【转】 1、什么是环形缓冲区 2、环形缓冲区的作用 3、程序编写测试(基于嵌入式linux的kmesg方式建立) 5、判断环形缓冲区的空或者满
本文转载自:http://blog.****.net/u013904227/article/details/51168398
- 环形缓冲区,顾名思义就是一个环状的存储数据的区域,其空间使用数组进行构造(链表也可以)。环形缓冲区特点是读和写可以是分开的,写入数据之后可以先不去读取,等到需要读取的时候再去读取,并且数据一经读取之后下次就不能再去读取(当然也可以实现重复读取的效果,不过大多用作一次性读取),等于说是一次性的读取。
- 假设一个长度为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
");
entry = create_proc_entry("mymsg", S_IRUSR, &proc_root);
if (entry)
entry->proc_fops = &proc_mymsg_operations;
// myprintk("Function printk_drv_init finished
");
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位置前面的一个字节始终不能够写入数据,但是却很轻易的区分出来缓冲区是满还是空