环形缓冲区,顾名思义这个缓冲区是环形的,那么何谓环形这个意思也很好理解,就是用一个指针去访问该缓冲区的最后一个内存位置的的后一位置时回到环形缓冲区的起点。类似一个环一样。这样形容就很好理解了,当然有办法实现了。我在这里采用了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系统中,缓冲区的保护机制就变得尤为重要了,因为我们的数据时不停的在读写,内存不停的变化,如果牵扯到多任务(多进程,多线程),我们就需要加锁对其进行保护措施。这里我在链表的实现下加了信号量加以保护。
1. #include <stdio.h>
2. #include <stdlib.h>
3. #include <pthread.h>
4. #include <semaphore.h>
5.
6. sem_t mutex;
7.
8. typedef struct
9. {
10. int
11. struct
12. }NODE;
13.
14. NODE *Create_loop_chain(int
15. {
16. int
17. NODE *head , *previous , *current ;
18. sizeof(NODE));
19. if(previous == NULL)
20. exit(1);
21.
22. previous->data =0;
23. previous->next = NULL;
24. head = previous ;
25.
26. for(i=0 ; i<n ; i++)
27. {
28. sizeof(NODE));
29. if(current == NULL)
30. exit(1);
31.
32. current->next = head;
33. previous->next = current;
34. previous = current ;
35. }
36. return
37. }
38.
39. int
40. {
41. NODE *current;
42. current = head->next ;
43. "List:/n");
44. while(current != head)
45. {
46. "%4d",current->data);
47. current = current->next;
48. }
49. "/n");
50. }
51.
52. int
53. {
54. NODE *current;
55. current = head->next;
56. while(1)
57. {
58. sem_wait(&mutex);
59. "read number is %d/n",current->data);
60. current = current->next;
61. sem_post(&mutex);
62. sleep(2);
63. }
64.
65. }
66.
67. int
68. {
69. NODE *current;
70. int
71. current = head->next;
72. while(1)
73. {
74. sem_wait(&mutex);
75. current->data = i++;
76. "write number is %d/n",current->data);
77. current = current->next;
78. sem_post(&mutex);
79. sleep(1);
80. }
81. }
82.
83. int main(int argc , char
84. {
85. int
86. char
87. NODE *head;
88. pthread_t id1,id2;
89.
90. ret = sem_init(&mutex ,0,1);
91. if(ret != 0){
92. "sem_init error");
93. }
94. "please input node_num /n");
95. "%d",&num);
96. head = Create_loop_chain(num);
97. "The ringbuf was found/n");
98. Show(head);
99.
100. void
101. void
102.
103. pthread_join(id1,NULL);
104. pthread_join(id2,NULL);
105.
106.
107. return
108. }