整理一下Scott的Circular Queue的设计

Circular Queue的作用

  • 在SRAM里面相当于是无限大的buffer. 实现基本都是下图所示:
    ringBuffer. 其中enqueue在Head, dequeue在tail. 且Head指向下一个插入的位置, Tail指向下一个可以读取的位置. 这样每次进来, 只要判断是否wrap, full. 然后就可以读写了.
  • 在一般来说是作为asynch thread communication. 见CS105: Harvey Mudd
  • 实现方式: github-Synchronization-CircularQueue.

Circular Queue的区别

  • wiki已经写了circular queue的几种实现方式, 区别在于判断empty/full的方式:

    1. head/tail+1 empty slot

      • 这个实现在: Ring Buffer_Anders Kaloer
      • Scott的Firmware里面的也是这样做的.
    2. head/tail+count

      • 一般都是用这个写, 因为简单, 而且semaphore其实就使这个count. 表示的是: 当前queue里面保存的item数量.
      • 我参考的Harshkn的写法. 改了一点. 主要是count在满了之后就不动了. 然后在push/pop里面加入了判断error的代码, 来自于kqchen.

实现代码

1. 使用Count

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
* https://gist.github.com/harshkn/909546
* C Implementation of simple circular buffer, Functionality provided are add to queue, read latest
*
* Implementation: head, tail, and count. The major different between AndersKaloer/Harshkn is the way to detect full/empty.
* The former trade with an empty slot, the latter use additional int->count. I review this because this is easier and Scott uses it too.
*/


typedef struct circular_buffer {
void *buffer; // data buffer
void *buffer_end; // end of data buffer
size_t capacity; // maximum number of items in the buffer
size_t count; // number of items in the buffer
size_t sz; // size of each item in the buffer
void *head; // pointer to head
void *tail; // pointer to tail
} circular_buffer;

void cb_init(circular_buffer *cb, size_t capacity, size_t sz) {
cb->buffer = malloc(capacity * sz);
if (cb->buffer == NULL) {
// handle error
}
cb->buffer_end = (char *) cb->buffer + capacity * sz;
cb->capacity = capacity;
cb->count = 0;
cb->sz = sz;
cb->head = cb->buffer;
cb->tail = cb->buffer;
}

void cb_free(circular_buffer *cb) {
free(cb->buffer);
// clear out other fields too, just to be safe
}

void cb_push_back(circular_buffer *cb, const void *item) {
if (cb->count == cb->capacity) {
printf("%s, %d: cb push back error. \n", __FILE__, __LINE__);
// return;
}
memcpy(cb->head, item, cb->sz);
printf("push data = %d\n", *(char *) cb->head);
cb->head = (char*) cb->head + cb->sz;
if (cb->head == cb->buffer_end)
cb->head = cb->buffer;
cb->count = cb->count == cb->capacity ? cb->count : cb->count + 1;
}

void cb_pop_front(circular_buffer *cb, void *item) {
if (cb->count == 0) {
printf("%s, %d: cb_pop_front: empty cb.\n", __FILE__, __LINE__);
return;
}
memcpy(item, cb->tail, cb->sz);
printf("pop data = %d\n", *(char *) cb->tail);
cb->tail = (char*) cb->tail + cb->sz;
if (cb->tail == cb->buffer_end)
cb->tail = cb->buffer;
cb->count--;
}

int cb_empty(circular_buffer *cb) {
if (cb->count == 0)
return 1;
return 0;
}

int cb_full(circular_buffer *cb) {
return cb->count == cb->capacity;
}

void printbuf(circular_buffer *cb) {
int i = 0;
for (; i < cb->capacity; ++i)
printf("%d ", *(char *) (cb->buffer + i));
}

/**
* https://github.com/kqchen/workspace/blob/21ab1c18dbf6c674437b0c89bb313ddbfc2de85c/hello/circular.c
*/

void cb_print(circular_buffer *cb) {
int cnt = cb->count;
do {
if (cb->count == 0) {
printf("%s, %d: cb is empty now.\n", __FILE__, __LINE__);
return;
}
printf("cb->tail=0x%x, cb->head=0x%x, cnt = %d\n", cb->tail, cb->head,
cnt);
cnt--;
} while (cnt > 0);
}
/**
* testing the ring buffer
*/

int main() {
circular_buffer tony; // a holder
cb_init(&tony, 4, 1);
int i = 10;
for (; i < 20; ++i) {
cb_push_back(&tony, &i);
// printf("%d with count: %d, data = %d\n", cb_full(&tony), tony.count, i);
}

printf("\nafter filling ---\n");
cb_print(&tony);
// printf("after filling ---\n");
// printbuf(&tony);
char result;
int j = 0;
for (; j < 6; ++j) {
cb_pop_front(&tony, &result);
// printf("%d with count: %d, result = %d\n", cb_empty(&tony), tony.count, result);
}
printf("\nafter pop ---\n");
cb_print(&tony);
return 0;
}

Comments

<<<<<<< Updated upstream ======= >>>>>>> Stashed changes <<<<<<< Updated upstream ======= >>>>>>> Stashed changes