环形缓冲区【转】

本文转载自: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位置前面的一个字节始终不能够写入数据,但是却很轻易的区分出来缓冲区是满还是空

posted @ 2017-08-01 14:32  请给我倒杯茶  阅读(430)  评论(0编辑  收藏  举报