浮萍晓生的开发日志

记录学习的旅程,把握可预见的未来

导航

环形缓冲区的设计与实现

Posted on 2014-03-20 10:06  浮萍晓生  阅读(820)  评论(0)    收藏  举报

  环形缓冲区是嵌入式系统中十分重要的一种数据结构,比如在一个视频处理的机制中,环形缓冲区就可以理解为数据码流的通道,每一个通道都对应着一个环形缓冲区,这样数据在读取和写入的时候都可以在这个缓冲区里循环进行,程序员可以根据自己需要的数据大小来决定自己使用的缓冲区大小。

  环形缓冲区,顾名思义这个缓冲区是环形的,那么何谓环形这个意思也很好理解,就是用一个指针去访问该缓冲区的最后一个内存位置的的后一位置时回到环形缓冲区的起点。类似一个环一样。这样形容就很好理解了,当然有办法实现了。我在这里采用了2种方式实现了环形缓冲区,一个是用数组的方法,一个是用链表的方法。

  数组是一块连续的内存,所以顺序访问时只要根据下标的增加而增加,但是最后一个元素之后需要回到起始位置,这就需要我们对这个地方进行特殊处理。只要最后一个地址访问结束能顺利回到起始地址,这个缓冲区就可以实现。代码如下:

/* File name: ringbuf.c
 * Author   : wanxiao
 * Function :Implement a circular buffer, 
             you can read and write data in the buffer zone.
 */

#include <stdio.h>   
  
#define MAXSIZE 8   
  
int ringbuf[MAXSIZE];   
int readldx=0;
int writeldx=0;

int next_data_handle(int addr)   
{   
    return (addr+1) == MAXSIZE ? 0:(addr+1) ;   
}   
  
int write_data(int data)
{
    int i;
    *(ringbuf+writeldx) = data;
    writeldx = next_data_handle(writeldx);
    for(i=0;i<MAXSIZE;i++)
    {
        printf("%4d",*(ringbuf+i));
        if(MAXSIZE-1 == i)
            printf("/n");
    }
}

int read_data()
{
    printf("read data is : %d/n",*(ringbuf+readldx));
    readldx = next_data_handle(readldx);
}
  
int main(int argc , char **argv)   
{   
    int data;   
    char cmd;

    do{   
        printf("select:/nw/t--write/nr/t--read/nq/t--quit/n");   
        scanf("%s",&cmd);   
  
        switch(cmd)   
        {   
            case 'w' :   
                printf("please input data:");   
                scanf("%d",&data);   
                write_data(data);   
                break;   
            case 'r' :   
                data = read_data();   
                break;   
            case 'q' :   
                printf("quit/n");   
                break;   
            default :   
                printf("Command  error/n");   
        }   
    }while(cmd != 'q');   
    return 0;   
}

 

链表实现,实际上就是一个单向循环链表。这个方法的优点是不需要最后一个元素进行特殊处理,但是实现起来比数组稍微麻烦一点,单思路还是很清晰简单的。代码如下:

#include <stdio.h>
#include <stdlib.h>


typedef struct signal_loop_chain
{
    int data;
    struct signal_loop_chain *next;
}NODE;

NODE *Create_loop_chain(int n)
{
    int i;
    NODE *head , *previous , *current ;
    previous = (NODE *)malloc(sizeof(NODE));
    if(previous == NULL)
        exit(1);

    previous->data =0;
    previous->next = NULL;
    head = previous ;

    for(i=0 ; i<n ; i++)
    {
        current = (NODE*)malloc(sizeof(NODE));
        if(current == NULL)
            exit(1);

//        scanf("%d",¤t->data);
        current->next = head;
        previous->next = current;
        previous = current ;
    }
    return head ;
}

int Show(NODE *head)
{
    NODE *current;
    current = head->next ;
    printf("List:/n");
    while(current != head)
    {
        printf("%4d",current->data);
        current = current->next;
    }
    printf("/n");
}

int read_buf(NODE *head)
{
    NODE *current;
    current = head->next;
    while(1)
    {
        printf("read number is %d/n",current->data);
        current = current->next;
        sleep(1);
    }

}

int write_buf(NODE *head)
{
    NODE *current;
    int i = 0;
    current = head->next;
    while(1)
    {
        current->data = i++;
        printf("write number is %d/n",current->data);
        current = current->next;
        sleep(1);
    }
}

int main(int argc , char **argv)
{
    int num;
    char cmd;
    NODE *head;
    printf("please input node_num /n");
    scanf("%d",&num);
    head = Create_loop_chain(num);
    printf("The ringbuf was found/n");
    Show(head);

    while(1){
        printf("please select r or w/n");
        scanf("%c",&cmd);

        if(cmd == 'r'){
            read_buf(head);
            Show(head);
        }
        
        if(cmd == 'w'){
            write_buf(head);
            Show(head);
        }
        
    }
    return 0;
}

以上都是针对单进程而言。对于系统,尤其是嵌入式Linux系统中,缓冲区的保护机制就变得尤为重要了,因为我们的数据时不停的在读写,内存不停的变化,如果牵扯到多任务(多进程,多线程),我们就需要加锁对其进行保护措施。这里我在链表的实现下加了信号量加以保护。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

sem_t mutex;

typedef struct signal_loop_chain
{
    int data;
    struct signal_loop_chain *next;
}NODE;

NODE *Create_loop_chain(int n)
{
    int i;
    NODE *head , *previous , *current ;
    previous = (NODE *)malloc(sizeof(NODE));
    if(previous == NULL)
        exit(1);

    previous->data =0;
    previous->next = NULL;
    head = previous ;

    for(i=0 ; i<n ; i++)
    {
        current = (NODE*)malloc(sizeof(NODE));
        if(current == NULL)
            exit(1);

        current->next = head;
        previous->next = current;
        previous = current ;
    }
    return head ;
}

int Show(NODE *head)
{
    NODE *current;
    current = head->next ;
    printf("List:/n");
    while(current != head)
    {
        printf("%4d",current->data);
        current = current->next;
    }
    printf("/n");
}

int read_buf(NODE *head)
{
    NODE *current;
    current = head->next;
    while(1)
    {
        sem_wait(&mutex);
        printf("read number is %d/n",current->data);
        current = current->next;
        sem_post(&mutex);
        sleep(2);
    }

}

int write_buf(NODE *head)
{
    NODE *current;
    int i = 0;
    current = head->next;
    while(1)
    {
        sem_wait(&mutex);
        current->data = i++;
        printf("write number is %d/n",current->data);
        current = current->next;
        sem_post(&mutex);
        sleep(1);
    }
}

int main(int argc , char **argv)
{
    int num,ret;
    char cmd;
    NODE *head;
    pthread_t id1,id2;

    ret = sem_init(&mutex ,0,1);
    if(ret != 0){
        perror("sem_init error");
    }
    printf("please input node_num /n");
    scanf("%d",&num);
    head = Create_loop_chain(num);
    printf("The ringbuf was found/n");
    Show(head);

    ret = pthread_create(&id1,NULL,(void *)write_buf,head);
    ret = pthread_create(&id2,NULL,(void *)read_buf,head);

    pthread_join(id1,NULL);
    pthread_join(id2,NULL);
    

    return 0;
}