综合技术
直播中

肖舒

7年用户 189经验值
私信 关注
[经验]

环形缓冲区的设计分享!

以下内容转自网络,感谢网友:玩笑joker
   
    环形缓冲区是嵌入式系统中十分重要的一种数据结构,比如在一个视频处理的机制中,环形缓冲区就可以理解为数据码流的通道,每一个通道都对应着一个环形缓冲区,这样数据在读取和写入的时候都可以在这个缓冲区里循环进行,程序员可以根据自己需要的数据大小来决定自己使用的缓冲区大小。
    环形缓冲区,顾名思义这个缓冲区是环形的,那么何谓环形这个意思也很好理解,就是用一个指针去访问该缓冲区的最后一个内存位置的的后一位置时回到环形缓冲区的起点。类似一个环一样。这样形容就很好理解了,当然有办法实现了。我在这里采用了2种方式实现了环形缓冲区,一个是用数组的方法,一个是用链表的方法。
    数组是一块连续的内存,所以顺序访问时只要根据下标的增加而增加,但是最后一个元素之后需要回到起始位置,这就需要我们对这个地方进行特殊处理。只要最后一个地址访问结束能顺利回到起始地址,这个缓冲区就可以实现。代码如下:
[cpp] view plaincopyprint?
  • /* File name: ringbuf.c
  • * Author: wanxiao
  • * Function:Implement a circular buffer,
  •              you can read and write data in the buffer zone.
  • */
  • #include
  • #define MAXSIZE 8
  • int ringbuf[MAXSIZE];
  • int readldx=0;
  • int writeldx=0;
  • int next_data_handle(int addr)
  • {
  •     return (addr+1) == MAXSIZE ? 0addr+1) ;
  • }
  • int write_data(int data)
  • {
  •     int i;
  •     *(ringbuf+writeldx) = data;
  •     writeldx = next_data_handle(writeldx);
  •     for(i=0;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;
  • }

    链表实现,实际上就是一个单向循环链表。这个方法的优点是不需要最后一个元素进行特殊处理,但是实现起来比数组稍微麻烦一点,单思路还是很清晰简单的。代码如下:
[cpp] view plaincopyprint?
  • #include
  • #include
  • 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    {
  •         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系统中,缓冲区的保护机制就变得尤为重要了,因为我们的数据时不停的在读写,内存不停的变化,如果牵扯到多任务(多进程,多线程),我们就需要加锁对其进行保护措施。这里我在链表的实现下加了信号量加以保护。
[c-sharp] view plaincopyprint?
  • #include
  • #include
  • #include
  • #include
  • 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    {
  •         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;
  • }

回帖(16)

王丽丽

2019-10-29 06:57:29
好东西啊,谢谢分享
举报

高群

2019-10-29 07:03:02
不错,谢谢分享。。。
举报

孙世珍

2019-10-29 07:14:30
在数组实现的时候我们使用
int next_data_handle(int addr)     
{  addr++;   
    addr%= MAXSIZE  ;     
}     
如果是通信的接收一组数据,数据未接收完成但到了数组的末尾,余下的数据要从数组的起始处存储;
这个时候有没有好的办法来判断数组接收完成。
举报

刘静焱

2019-10-29 07:28:17
我们在判断的时候使用的结构体。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分