RingBuffer是什么?
正如名字所说的一样,它是一个环(首尾相接的环),你可以把它用做在不同上下文(线程)间传递数据的buffer。
基本来说,ringbuffer拥有一个序号,这个序号指向数组中下一个可用的元素。
随着你不停地填充这个buffer(可能也会有相应的读取),这个序号会一直增长,直到绕过这个环。
我们选择用环形buffer的最初原因就是想要提供可靠的消息传递。我们需要将已经被服务发送过的消息保存起来,这样当另外一个服务通过nak (拒绝应答信号)告诉我们没有成功收到消息时,我们能够重新发送给他们。
下面介绍一下PX4源码中关于RingBuffer的数据写入与取值过程,代码如下
/**
* Ringbuffer.h
*
* int _head = _tail = 0;
* size = 21
*/
inline void push(data_type sample)
{
int head_new = _head;
if (_first_write) {
head_new = _head;
} else {
head_new = (_head + 1) % _size;
}
_buffer[head_new] = sample;
_head = head_new;
// move tail if we overwrite it
if (_head == _tail && !_first_write) {
_tail = (_tail + 1) % _size;
} else {
_first_write = false;
}
}
inline data_type get_oldest()
{
return _buffer[_tail];
}
unsigned get_oldest_index()
{
return _tail;
}
inline data_type get_newest()
{
return _buffer[_head];
}
整个写入过程中_head
和_tail
的变化过程如下表所示:
_head | _tail |
---|---|
0 | 0 |
1 | 0 |
2 | 0 |
… | 0 |
20 | 0 |
0 | 1 |
1 | 2 |
2 | 3 |
… | … |
n (<21) | n+1(<21) |
-
第一圈写入的时候,尾不变,头增加,
get_newest()
都是最新写入的数,在头部;get_oldest()
是第一个写入的数,在尾部。 -
写满一圈之后,
get_newest()
的依然是最新写入的、头部的数;而get_oldest()
则是上一圈序号大于当前序号的一个数。因为环形缓冲区的大小是固定的,具有数组的性质,写入的数据不会丢弃,一直保存在缓冲区中。