环形缓冲区的实现原理(ring buffer)
ringbuffer原理
![ringbuffer原理](https://img.taocdn.com/s3/m/13bdc24459fafab069dc5022aaea998fcc22409c.png)
ringbuffer原理
Ringbuffer是一种常用的数据结构,它可以有效地支持数据的
生产者和消费者在共享内存中进行数据交换。
它是一种高效率,高可靠性的内存技术,可以支持高效率的数据收集,分析和处理。
Ringbuffer可以用于消息队列,分布式计算,数据库集群以及
缓存等应用场景。
它解决了消息积压和处理性能瓶颈的问题,可以实现高吞吐量,低延迟快速数据交换。
Ringbuffer的原理是,它由一个循环的缓冲区构成,缓冲区内
的每个单元用于存储数据。
发送者和接收者可以通过指定的游标来读写这些数据,而且没有锁的概念,允许多个线程同时访问缓冲区,从而提高访问性能。
当缓冲区满时,发送者和接收者都会暂停,因此可以避免消息队列积压,保证数据传输的可靠性。
另一个优点是,Ringbuffer可以在如何存储数据方面提供更大
的灵活性,可以存储任意类型的数据,而不需要将数据进行补充封装。
最后,Ringbuffer可以提高发送和接收组件之间的可靠性,可
以让数据在一个有限的空间中得到高效地处理,同时仍然保持可靠性。
总而言之,Ringbuffer是一种强大的数据结构,可以有效地支
持数据的发送和接收,保持高性能,高可靠性,灵活性强,为现代应用场景提供了更多选择。
- 1 -。
ringbuffer原理
![ringbuffer原理](https://img.taocdn.com/s3/m/c631abf832d4b14e852458fb770bf78a65293ab2.png)
ringbuffer原理Ringbuffer(环形缓冲区)是一种常用的缓冲结构,它可以将收到的数据存储在一个环状的结构中。
Ringbuffer可以存储一个指定大小的有序列表,以便可以在添加元素时移除最旧的元素。
它可以实现读取/输入的快速操作,并且通常用于实现某种消息队列,以便异步处理消息和任务。
Ringbuffer通常由一组数组,称为环形缓冲区,组成,其中每个缓冲区具有特定的大小,以存储一定数量的数据。
当新数据加入Ringbuffer时,其中最旧的数据将被替换掉,以便容纳新数据。
这种有限长度的缓冲区可以避免在存储缓冲区数据时产生内存碎片,并且可以提高缓冲区的操作效率和可靠性。
Ringbuffer的工作原理基本上是通过两个索引,一个用于读取数据,另一个用于写入数据,来实现的。
在使用这两个索引来实现缓冲操作时,当一个索引指向的位置超出缓冲区大小时,它就会被重置为0,而另一个索引则会继续向前移动,以便确保新数据能够按顺序连续存储在缓冲区中。
Ringbuffer缓冲区非常适用于处理大量数据,因为它们能够高效地管理数据。
它们可以在很短的时间内处理大量数据,这使它们很容易取代其他缓冲区技术。
此外,它们还可以实现数据的可靠性,因为它们可以确保数据在被替换之前被完全处理。
另外,Ringbuffer缓冲区可以更有效地利用系统资源,因为它们可以减少系统需要处理的内存量,从而也可以减少产生的内存碎片。
它们还可以使数据处理更简单,并且可以显著提高系统的操作效率。
总而言之,Ringbuffer缓冲区是一种非常有用的数据存储和管理结构,可以提高系统的性能,同时减少系统资源的消耗。
因此,它们已经广泛应用于许多系统,用于大规模数据处理,并且还在不断发展中。
环形缓冲区的基本原理
![环形缓冲区的基本原理](https://img.taocdn.com/s3/m/b6a203505bcfa1c7aa00b52acfc789eb162d9e4d.png)
环形缓冲区的基本原理
环形缓冲区的基本原理:
原理是将一个固定大小的缓冲区看作一个首尾相连的环形结构,在该结构中,数据的读写操作可以按照先进先出(FIFO)的原则进行,即最先写入的数据最先被读出,最后写入的数据最后被读出。
具体来说,环形缓冲区由三个基本元素组成:
一个固定大小的缓冲区,通常是一个连续的内存区域。
一个读指针(也称为"头指针"),指向下一个要被读取的数据。
一个写指针(也称为"尾指针"),指向下一个要被写入的数据。
当环形缓冲区为空时,读指针和写指针重合。
当有新数据写入到环形缓冲区时,该数据被写入到写指针所指示的位置,同时写指针向后移动一位,等待下次写入。
当读取数据时,数据被读取到读指针所指示的位置,同时读指针向后移动一位。
当写指针超过缓冲区的末尾时,它将回到缓冲区的开头,从而形成一个环形结构。
此时,如果读指针没有跟上写指针,读操作将无法继续。
为了解决这个问题,可以采用两种策略:一是等待缓冲区有足够的空间,二是覆盖最早写入的数据。
这些策略可以根据具体情况和应用场景进行选择。
环形缓冲区 c语言 实现
![环形缓冲区 c语言 实现](https://img.taocdn.com/s3/m/7e101684d0f34693daef5ef7ba0d4a7303766c7d.png)
环形缓冲区 c语言实现环形缓冲区是一种常用的数据结构,可以用于在数据的不断产生和消费过程中,存储和管理数据。
在C语言中,实现环形缓冲区可以采用数组的方式来存储数据,具体实现过程如下。
1.首先需要定义一个环形缓冲区的结构体,包括环形缓冲区的大小、头部指针和尾部指针等信息。
例如:```ctypedef struct {uint8_t *buffer; //缓冲区地址uint32_t size; //缓冲区大小uint32_t in; //头部指针uint32_t out; //尾部指针} ring_buffer_t;```2.初始化缓冲区,为环形缓冲区指针分配内存。
例如:```cvoid ring_buffer_init(ring_buffer_t *ring_buffer, uint8_t*buffer, uint32_t size) {ring_buffer->buffer = buffer;ring_buffer->size = size;ring_buffer->in = 0; //初始化头指针为0ring_buffer->out = 0; //初始化尾指针为0}```3.向环形缓冲区写入数据。
如果缓冲区已满,需要等待缓冲区有空位;如果缓冲区未满,则将数据写入缓冲区尾部,并将尾指针向后移动一个位置。
例如:```cvoid ring_buffer_write(ring_buffer_t *ring_buffer, uint8_t*data, uint32_t length) {for (uint32_t i = 0; i < length; i++) {//判断缓冲区是否已满if (((ring_buffer->in + 1) % ring_buffer->size) != ring_buffer->out) {//写入数据ring_buffer->buffer[ring_buffer->in] = data[i]; //移动头指针ring_buffer->in = (ring_buffer->in + 1) %ring_buffer->size;} else {//缓冲区已满,等待有空位}}}```4.从环形缓冲区读取数据。
hadoop 环形缓冲区 原理
![hadoop 环形缓冲区 原理](https://img.taocdn.com/s3/m/f96efb576d175f0e7cd184254b35eefdc9d31578.png)
hadoop 环形缓冲区原理Hadoop环形缓冲区是Hadoop框架中的一个重要组件,用于在数据传输和处理过程中提供高效的缓冲机制。
它的原理如下:1. 数据分块,在Hadoop中,数据会被分成多个块进行处理,每个块的大小一般为默认的128MB,但也可以根据需求进行配置。
这些数据块会在集群中的不同节点之间进行传输和处理。
2. 环形缓冲区的结构,Hadoop环形缓冲区是一个环形的字节数组,它被用来存储数据块。
环形缓冲区由多个等大小的缓冲区组成,每个缓冲区被称为一个“帧”。
帧的大小一般为64KB,同样可以根据需要进行配置。
3. 缓冲区的分配和释放,当数据块需要传输或处理时,Hadoop 会为其分配一个或多个帧的缓冲区。
这些缓冲区被用来存储数据块的片段,每个片段大小与帧的大小相同。
一旦数据块的传输或处理完成,缓冲区会被释放,以供其他数据块使用。
4. 环形缓冲区的循环使用,环形缓冲区是循环使用的,即一旦缓冲区的末尾被使用,数据会从缓冲区的开头继续写入。
这种循环使用的机制可以有效地减少内存的占用,并提高数据传输和处理的效率。
5. 读写指针的管理,为了实现环形缓冲区的循环使用,Hadoop 使用了读写指针来管理缓冲区的读写位置。
读指针指示下一个可读取的位置,写指针指示下一个可写入的位置。
通过适当地管理读写指针,可以确保数据的正确读取和写入。
6. 数据传输和处理,一旦数据块的缓冲区准备就绪,数据就可以被传输到目标节点进行处理。
在传输过程中,数据会被分成多个片段,每个片段被写入一个帧的缓冲区中。
目标节点会读取这些缓冲区中的数据,并进行相应的处理。
总结起来,Hadoop环形缓冲区通过循环使用的机制和读写指针的管理,提供了高效的数据传输和处理机制。
它可以减少内存的占用,提高数据处理的效率,是Hadoop框架中重要的组成部分之一。
linux 管道的环形buffer(缓冲区) 实现原理
![linux 管道的环形buffer(缓冲区) 实现原理](https://img.taocdn.com/s3/m/ef9243bb05a1b0717fd5360cba1aa81144318f92.png)
linux 管道的环形buffer(缓冲区)实现原理标题:Linux管道的环形缓冲区(缓冲区)实现原理在Linux系统中,管道(Pipe)是一种常用的进程间通信方式,主要用于在父子进程之间或者同时运行的进程之间进行数据交换。
而在管道的实现中,环形缓冲区(Buffer)扮演了重要的角色。
本文将详细介绍Linux管道的环形缓冲区的实现原理。
一、环形缓冲区的概念环形缓冲区,也称为循环缓冲区,是一种数据结构,其特点是当数据写入或读取到达缓冲区的末端时,新的数据可以继续在缓冲区的开始处写入或读取,形成一个循环。
这种数据结构在管道、队列等场景中广泛应用。
二、Linux管道的环形缓冲区实现原理1. 缓冲区分配:Linux系统为管道分配一个环形缓冲区,大小由管道的大小参数决定。
缓冲区通常以字节为单位进行操作。
2. 数据传输:当一个进程通过管道向另一个进程发送数据时,数据首先被写入缓冲区。
进程间通过特定的系统调用(如read和write)进行数据传输,这些调用会检查缓冲区是否有可用的空间,如果有,则从缓冲区读取或写入数据;如果没有,则等待直到有空间可用。
3. 缓存溢出处理:为了避免数据丢失,当缓冲区已满时,新写入的数据会被丢弃。
Linux系统会根据一定的策略(如最近最少使用算法)来决定丢弃哪个数据。
同时,如果读进程无法从缓冲区读取数据,Linux系统会触发一个信号(信号处理函数通常会重置读指针并通知进程)通知读进程缓冲区已空。
4. 线程安全:Linux系统中的管道通常是由内核线程管理的,因此环形缓冲区的操作通常是线程安全的。
多个进程可以同时读写同一个管道,而不会出现数据竞争或冲突的情况。
5. 内存管理:环形缓冲区的内存通常由操作系统进行管理。
当一个进程不再需要使用一个环形缓冲区时,它应该将其释放以供其他进程使用。
三、环形缓冲区的优化为了提高性能和效率,Linux系统对环形缓冲区进行了许多优化:1. 缓存预取:当一个进程将要写入大量数据时,Linux系统会预先从磁盘读取缓冲区所需的数据,以减少磁盘I/O操作。
ringbuffer原理
![ringbuffer原理](https://img.taocdn.com/s3/m/5508c24e793e0912a21614791711cc7931b7781a.png)
ringbuffer原理ringbuffer是一种常用的数据结构,它可以在多线程,网络帧等应用场景中得到广泛应用。
一般来说,ringbuffer是一个环形缓冲区,其大小是固定的,可以放入入口再取出出口,但是若缓冲区满了则溢出,若缓冲区空则无法取出数据,出现阻塞。
一般情况下,ringbuffer由一个指向缓冲区前面的指针,一个指向当前缓冲区的首地址的指针和一个指向缓冲区尾地址的指针组成,当ringbuffer满时,前向指针指向缓冲区最后一个字节,后向指针指向缓冲区首地址。
当ringbuffer空时,前向指针和后向指针指向相同的位置,且该位置恰好为空。
其中,还有一种ringbuffer,即双缓冲区ringbuffer,即具有两个缓冲区:一个缓冲区用来存放数据,另一个缓冲区用来存放指向缓冲区前面和后面的指针。
ringbuffer的使用受限于缓冲区的大小,由于它具有缓冲的特性,可以减少多线程的执行时间,从而提高系统的效率。
由于ringbuffer支持FIFO(First-In-First-Out)机制,可以保证读写数据的一致性,避免数据的延迟,从而提高多线程的开发效果。
此外,ringbuffer具有索引,可以直接查找缓冲区中的指定数据,从而加快数据的处理速度。
由于ringbuffer支持不同类型的数据,因此,它可以应用于许多不同领域。
例如,在媒体播放应用中,ringbuffer用来缓存媒体流,以避免实时网络传输中的延迟和不稳定;在游戏开发应用中,ringbuffer用来存放游戏对象,以实现命令驱动的复杂游戏;在通信应用中,ringbuffer用来存放网络帧,以便高效的处理数据。
总的来说,ringbuffer是一种非常有效的数据结构,它具有良好的性能,可以用来处理多线程,网络帧等复杂的任务。
ringbuffer 对于某些应用来说是必须的,它不仅可以提高程序性能,而且可以增强数据安全性,从而使程序更加可靠可用。
disruptor源码解析(超详细注释)
![disruptor源码解析(超详细注释)](https://img.taocdn.com/s3/m/a3763551cd7931b765ce0508763231126edb771e.png)
disruptor源码解析(超详细注释)《Disruptor源码解析(超详细注释)》引言:Disruptor是一种高性能的并发编程框架,其核心思想是通过无锁的环形缓冲区来实现线程间的高效通信。
本文将对Disruptor的源码进行详细解析,并加上适当的注释,以便读者能够更好地理解其原理和实现。
一、Disruptor的基本概念1.1 环形缓冲区Disruptor通过环形缓冲区来实现线程间的数据交换。
环形缓冲区由一组预分配的元素(Event)组成,每个元素都包含一个具体的数据项。
生产者(Producer)可以将数据写入缓冲区的空闲位置,而消费者(Consumer)则可以读取缓冲区中的数据。
1.2 序列(Sequence)序列用于标识缓冲区中的某个位置,每个生产者和消费者都会维护一个序列。
生产者使用序列来记录其下一个要写入的位置,而消费者则使用序列来记录其下一个要读取的位置。
序列的更新是通过CAS原子操作来实现的,因此可以避免使用锁。
1.3 生产者序列(Producer Sequence)生产者序列用于记录生产者的当前位置。
当生产者将数据写入缓冲区后,会更新其生产者序列,表示数据已经被写入。
1.4 消费者序列(Consumer Sequence)消费者序列用于记录消费者的当前位置。
当消费者读取缓冲区中的数据后,会更新其消费者序列,表示数据已经被消费。
二、Disruptor的核心组件2.1 RingBufferRingBuffer是Disruptor的核心数据结构,它是一个环形缓冲区,用于存储数据。
RingBuffer的大小是固定的,一旦初始化就不能改变。
RingBuffer内部使用数组来存储元素,通过序列来标识数组中的位置。
2.2 SequenceBarrierSequenceBarrier用于保证消费者读取数据的顺序性。
当生产者写入数据时,消费者需要等待所有生产者的数据都被写入后才能读取。
SequenceBarrier内部通过监控生产者序列和消费者序列来实现等待机制。
stm32串口环形缓冲区开发实例代码
![stm32串口环形缓冲区开发实例代码](https://img.taocdn.com/s3/m/b49249622e60ddccda38376baf1ffc4fff47e255.png)
stm32串口环形缓冲区开发实例代码【STM32串口环形缓冲区开发实例代码】近年来,随着物联网技术的快速发展,嵌入式系统的需求日益增加。
而在嵌入式系统中,串口通信一直都是一项非常重要的功能。
而在使用串口通信时,我们经常会遇到一个问题,即数据接收和发送的速度不匹配导致数据丢失的情况。
为了解决这个问题,我们可以使用环形缓冲区来进行数据的存储和管理。
本文将以STM32单片机为例,介绍如何开发串口环形缓冲区,并给出相应的实例代码。
一、环形缓冲区的原理环形缓冲区是一种循环队列,它具有固定的大小,并且在填满数据后会自动循环覆盖之前的数据。
这种数据结构可以很好地解决数据接收和发送速度不匹配的问题。
在串口通信中,我们可以将接收到的数据存储到环形缓冲区中,在发送数据时,则可以从环形缓冲区中取出数据进行发送。
二、环形缓冲区的实现在STM32单片机中,我们可以通过使用指针和数组来实现环形缓冲区。
我们需要定义缓冲区的大小,然后创建两个指针,分别指向缓冲区的头部和尾部。
当接收到新的数据时,我们将数据存储到尾部指针所指向的位置,并将尾部指针向后移动一个位置。
当需要取出数据进行发送时,我们则从头部指针所指向的位置取出数据,并将头部指针向后移动一个位置。
需要注意的是,当头部指针和尾部指针相遇时,表示缓冲区已满,此时需要进行循环覆盖操作。
下面是一个基于STM32的串口环形缓冲区的实例代码:```c#include "stm32f4xx.h"#define BUFFER_SIZE 256volatile uint8_t rx_buffer[BUFFER_SIZE];volatile uint8_t tx_buffer[BUFFER_SIZE];volatile uint16_t rx_head = 0, rx_tail = 0;volatile uint16_t tx_head = 0, tx_tail = 0;void USART2_IRQHandler(void){if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {rx_buffer[rx_head] = USART_ReceiveData(USART2);rx_head = (rx_head + 1) % BUFFER_SIZE;}if(USART_GetITStatus(USART2, USART_IT_TXE) != RESET) {if(tx_head != tx_tail){USART_SendData(USART2, tx_buffer[tx_tail]);tx_tail = (tx_tail + 1) % BUFFER_SIZE;}else{USART_ITConfig(USART2, USART_IT_TXE, DISABLE); }}}void send_data(uint8_t data){tx_buffer[tx_head] = data;tx_head = (tx_head + 1) % BUFFER_SIZE;USART_ITConfig(USART2, USART_IT_TXE, ENABLE);}```在上面的代码中,我们定义了两个缓冲区rx_buffer和tx_buffer,并分别设置了头部指针和尾部指针rx_head、rx_tail和tx_head、tx_tail。
单片机环形缓冲区
![单片机环形缓冲区](https://img.taocdn.com/s3/m/75c2cc37e97101f69e3143323968011ca300f7e9.png)
单片机环形缓冲区
单片机环形缓冲区是一种常用的数据存储方式,它具有循环利用空间的特点,可以有效地解决数据存储和传输过程中的数据拥塞问题。
在实际应用中,环形缓冲区常用于串口通信、音频处理、图像处理等领域。
环形缓冲区的实现原理是通过两个指针来确定缓冲区的起始位
置和结束位置,当数据写入缓冲区时,写指针指向的位置不断向后移动,当写指针到达缓冲区的末尾时,它就会自动回到缓冲区的起始位置,实现数据的循环存储。
当需要读取数据时,读指针指向的位置也会不断向后移动,当读指针到达写指针所在的位置时,说明已经读取了所有的数据,此时可以重新开始写入新的数据。
在使用环形缓冲区时,需要注意以下几点:
1. 缓冲区的大小应该预留一定的空间,以防止缓冲区溢出。
2. 在读取数据时,需要判断是否已经读取了所有的数据,避免
出现数据重复读取的情况。
3. 在写入数据时,需要判断缓冲区是否已满,如果已满,需要
采取相应的措施,如丢弃部分数据或者等待缓冲区有空闲空间。
4. 当多个任务同时访问缓冲区时,需要采取相应的同步措施,
以避免数据冲突和竞争条件。
总之,单片机环形缓冲区是一种简单、高效、可靠的数据存储方式,它在各种嵌入式应用中都得到了广泛的应用。
掌握环形缓冲区的实现原理和使用方法,对于提高系统的性能和可靠性具有重要的意义。
乒乓buffer原理
![乒乓buffer原理](https://img.taocdn.com/s3/m/caf9c232bfd5b9f3f90f76c66137ee06eef94e44.png)
乒乓buffer原理引言:乒乓buffer是许多计算机网络中常用的一种技术,利用它可以提高网络传输的速度和效率。
本文将从原理、分类、工作原理和应用等方面详细介绍乒乓buffer这一重要技术。
一、原理乒乓缓存,也被称为环形缓冲或循环缓冲,是一种双向的缓冲技术,其中一个缓冲用于读取,另一个缓冲用于写入。
使用两个缓冲器是为了保证在读写过程中不会出现冲突,提高了读写的并发度。
当写入的数据量达到缓冲大小时,将数据写到另一个缓冲区,同时启动读取操作。
这样,一口气写入的数据可以分成多个块进行传输,使得系统更加稳定。
二、分类乒乓缓冲的分类有两种,可以分为硬件乒乓缓冲和软件乒乓缓冲。
硬件乒乓缓冲:硬件乒乓缓冲在网络接口卡上实现。
这种技术可以有效地控制网络闪断,提供更高的数据传输效率。
这种缓冲技术也是现在最流行的技术之一。
软件乒乓缓冲:软件乒乓缓冲是指利用软件控制数据流动,将数据先放入缓冲区后,再进行下一步操作。
软件乒乓缓冲通常是在操作系统网络协议栈内完成,这种技术可以改善网络的传输性能。
三、工作原理当数据到达写缓冲区时,它被存储在缓冲区中。
接着,系统启动一个中断,向应用程序发送一个通知,表明数据已经到达缓冲区了。
程序随后会立即去读取这些数据。
一旦读取过程开始,数据就从读缓存区中流出,每个字节被读取并流转到应用程序中。
一旦全部读取完成,程序将数据从缓冲区中清除,这样,数据就可以被再次写入缓存。
四、应用乒乓缓冲是网络设备中常见的技术,它可以提高网络的吞吐量和性能。
例如,在路由器或交换机中,它可以增加数据包的传输速度。
同时,在音视频传输中,乒乓缓冲也是非常重要的,它可以确保音视频的流畅传输。
结论:通过本文的介绍,我们了解了乒乓缓冲这一重要技术的原理、分类、工作原理和应用场景。
在许多网络设备中,乒乓缓冲技术可以提高网络传输的效率和稳定性,为我们生活中的网络通讯提供了可靠的保障。
内存环形缓冲区ringbuffer
![内存环形缓冲区ringbuffer](https://img.taocdn.com/s3/m/ee395bd28ad63186bceb19e8b8f67c1cfbd6ee45.png)
内存环形缓冲区ringbufferRealTouch评估板RT‐Thread入门文档版本号:1.0.0日期:2012/8/14修订记录日期 作者 修订历史2012/8/14 bloom5 创建文档实验目的❑快速了解ringbuffer相关背景知识❑掌握了解ringbuffer相关API硬件说明本实验使用RT-Thread官方的Realtouch开发板作为实验平台。
涉及到的硬件主要为❑串口3,作为rt_kprintf输出,需要连接JTAG扩展板具体请参见《Realtouch开发板使用手册》实验原理及程序结构Ringbuffer的数据结构struct rt_ringbuffer{rt_uint16_t read_index, write_index;rt_uint8_t *buffer_ptr;rt_uint16_t buffer_size;};环形Buffer的特点:通常包含一个读指针(read_index)和一个写指针(write_index)。
读指针指向环形Buffer中第一个可读的数据,写指针指向环形Buffer中第一个可写的缓冲区。
通过移动读指针和写指针就可以实现Buffer的数据读取和写入。
在通常情况下,环形Buffer的读用户仅仅会影响读指针,而写用户也仅仅会影响写指针。
环形Buffer的原理:首先在内存里开辟一片区域(大小为buffer_size),对于写用户,顺序往Buffer里写入东西,直到写满为止;对于读用户,顺次从Buffer里读出东西,直到读空为止。
有效存储空间与buffer_size的区别:有效存储空间是指那些没有存放数据,或者以前存放过但已经处理过的数据,就是可用的空间大小;而buffer_size指的是总大小。
通过上面介绍可知,环形Buffer 在物理上仍然是一块连续的内存Buffer,只不过其空间会被循环使用而已。
示意图如下,根据读写指针的位置可分为两种情况,其中阴影填充部分为数据/已用空间,空白区域为可用空间,即有效存储空间。
linux 管道的环形buffer(缓冲区) 实现原理 -回复
![linux 管道的环形buffer(缓冲区) 实现原理 -回复](https://img.taocdn.com/s3/m/d7232e4c773231126edb6f1aff00bed5b8f37360.png)
linux 管道的环形buffer(缓冲区)实现原理-回复Linux管道是一种非常有用的工具,可以在不同的进程之间进行通信。
它使用了环形缓冲区的实现原理,让我们一起深入探讨一下这个原理。
一、环形缓冲区的定义环形缓冲区,又叫"环形队列"或"循环缓冲区",是一种用于存储和传输数据的数据结构。
它的特点是固定大小,一旦缓冲区被填满,写入数据会覆盖最早的数据,使得缓冲区可以继续存储新的数据。
环形缓冲区常用于高速数据传输和实时数据处理,流水线处理等场景。
二、管道的基本原理1. 管道的创建当我们在Linux中创建一个管道时,实际上会创建一个环形缓冲区,并返回两个文件描述符:一个用于读取数据,一个用于写入数据。
这样,我们就可以在不同的进程之间进行通信了。
2. 管道的读写操作在管道中,写入操作和读取操作是互斥的,即同一时间只能有一个进程进行写入,另一个进行读取。
当一个进程写入数据到环形缓冲区时,数据会被保存在缓冲区的尾部,同时尾指针会指向下一个可以写入的位置。
当另一个进程读取数据时,数据会从缓冲区的头部开始读取,同时头指针也会指向下一个可以读取的位置。
这样,读取的数据会被删除,腾出空间给新的数据。
3. 管道的容量限制由于环形缓冲区有固定的大小,因此管道的容量也是有限的。
当缓冲区已满时,写入操作就会阻塞,直到有足够的空间可以写入数据。
同样地,当缓冲区为空时,读取操作也会阻塞,直到有新的数据被写入。
三、管道的实现细节1. 管道的数据结构在Linux内核中,管道被实现为一对相互连接的文件描述符。
这对文件描述符分别代表了管道的读取端和写入端。
它们通过文件系统的抽象接口进行通信,但实际上并不涉及真实的磁盘读写操作。
2. 管道的缓冲区管道的缓冲区是由内核在内存中分配的一段连续空间,用于存储数据。
在创建管道时,内核会分配缓冲区,并初始化两个指针:头指针和尾指针。
头指针指向缓冲区的起始位置,尾指针指向缓冲区的末尾。
数据结构环状缓冲区(ring_buffer)的实现
![数据结构环状缓冲区(ring_buffer)的实现](https://img.taocdn.com/s3/m/d8595145e518964bcf847cc6.png)
{
if (this != &other)
{
RingBuffer<N> temp(other);
// invoke copy constructor
swap(temp);
// this->swap();
}
return (*this);
}
/** * ACCESSORS */
bool is_full() const {
* @param length : The length of the data that will be written.
* @return : The real length that had been written into this ring buffer.
*
If there are no enough free space in the ring buffer or the specified
namespace Utility {
//-----------------------------------------------------------------------// This is an accumulated buffer, it can store any object or scattered data. // It is said that, this buffer can receive some bytes of any length at one // time by push operation, as long as there are enough free space. And you can
*
|________| |
ringbuffer原理
![ringbuffer原理](https://img.taocdn.com/s3/m/925413c4afaad1f34693daef5ef7ba0d4a736de0.png)
ringbuffer原理Ringbuffer是一种可以自动地重复使用内存空间的缓冲方式,比传统的缓冲方式更具可移植性和可扩展性。
它也有助于保持应用程序的性能,因为它可以提高内存利用率和内存读写速度。
它主要用于多线程环境中的缓冲方式,它可以实现多个线程之间的快速交换数据。
Ringbuffer的核心思想是一个环形缓冲区,将循环链接起来。
它以一个始终不变的存储空间作为其边界,以一定的容量分割成区块,每个区块存储一个数据项。
一旦环形缓冲区满了,任何新的数据都将覆盖原来的数据,从而实现对旧数据的替换。
当READER从Ringbuffer读取数据时,它只能从缓存中读取未更新的数据,而WRITER则只能覆盖先前缓存的旧数据,以便保证数据的准确性和一致性。
通常,ringbuffer使用两个指针来标记缓冲区中被读取和被写入的位置,READER一次读取一个数据,WRITER一次写入一个数据,这就是Ringbuffer的基本原理。
Ringbuffer的优点是,它能够以高性能的方式实现内存池的概念。
这意味着仅在需要使用时,才给内存分配,而不是反复分配和释放,从而提高系统性能。
另外,ringbuffer可以实现多线程数据处理,因为它可以分配多个数据节点。
此外,ringbuffer还可以减少内存碎片,因为它使用固定大小的内存,并且每次仅在必要的时候才分配,以减少碎片化的影响。
另外,ringbuffer可以将现有的内存空间有效地分配给多个线程,从而进一步提升系统的性能。
总的来说,ringbuffer在缓存、内存管理和多线程处理方面都是非常有用的技术。
它可以帮助应用程序更有效地利用已有的内存空间,提高系统性能,并减少内存碎片。
此外,ringbuffer也提供了一种可扩展性和可移植性的缓冲方式,可以实现多线程应用程序的高效处理。
环形缓冲区的实现原理(ring buffer)
![环形缓冲区的实现原理(ring buffer)](https://img.taocdn.com/s3/m/46bc49f37c1cfad6195fa75f.png)
pBuf = new _Type[512];//默认 512 m_capacity = 512; } template <class _Type> CShareQueue<_Type>::CShareQueue(unsigned int bufsize) : m_head(0), m_tail(0) { if( bufsize > 512 || bufsize < 1) { pBuf = new _Type[512]; m_capacity = 512; } else { pBuf = new _Type[bufsize]; m_capacity = bufsize; } } template <class _Type> CShareQueue<_Type>::~CShareQueue() { delete[] pBuf; pBuf = NULL; m_head = m_tail = m_size = m_capacity = 0; } //前面弹出一个元素 template <class _Type> _Type CShareQueue<_Type>::pop_front() { if( IsEmpty() ) { return NULL; } _Type itemtmp; itemtmp = pBuf[m_head]; m_head = (m_head + 1) % m_capacity; --m_size; return itemtmp; } //从尾部加入队列 template <class _Type>
个
数
据
。
2、实例:环形缓冲区的实现 环形缓冲区是数据通信程序中使用最为广泛的数据结构之一,下面的代码,实现了一个环形缓冲区: /*ringbuf .c*/ #include<stdio. h>
环形缓冲器(FIFO)
![环形缓冲器(FIFO)](https://img.taocdn.com/s3/m/a5448e2c86c24028915f804d2b160b4e767f8189.png)
环形缓冲器(FIFO)圆形缓冲区(circular buffer),也称作圆形队列(circular queue),循环缓冲区(cyclic buffer),环形缓冲区(ring buffer),是⼀种数据结构⽤于表⽰⼀个固定尺⼨、头尾相连的缓冲区,适合缓存数据流。
⽬录1 ⽤法2 ⼯作过程3 圆形缓冲区⼯作机制3.1 读指针与写指针3.2 区分缓冲区满或者空3.2.1 总是保持⼀个存储单元为空3.2.2 使⽤数据计数3.2.3 镜像指⽰位3.2.4 读/写计数3.2.5 记录最后的操作3.3 POSIX优化实现3.4 Linux内核的kfifo4 外部链接⽤法圆形缓冲区的⼀个有⽤特性是:当⼀个数据元素被⽤掉后,其余数据元素不需要移动其存储位置。
相反,⼀个⾮圆形缓冲区(例如⼀个普通的队列)在⽤掉⼀个数据元素后,其余数据元素需要向前搬移。
换句话说,圆形缓冲区适合实现先进先出缓冲区,⽽⾮圆形缓冲区适合后进先出缓冲区。
圆形缓冲区适合于事先明确了缓冲区的最⼤容量的情形。
扩展⼀个圆形缓冲区的容量,需要搬移其中的数据。
因此⼀个缓冲区如果需要经常调整其容量,⽤链表实现更为合适。
写操作覆盖圆形缓冲区中未被处理的数据在某些情况下是允许的。
特别是在多媒体处理时。
例如,⾳频的⽣产者可以覆盖掉声卡尚未来得及处理的⾳频数据。
⼯作过程⼀个圆形缓冲区最初为空并有预定的长度。
例如,这是⼀个具有七个元素空间的圆形缓冲区,其中底部的单线与箭头表⽰“头尾相接”形成⼀个圆形地址空间:假定1被写⼊缓冲区中部(对于圆形缓冲区来说,最初的写⼊位置在哪⾥是⽆关紧要的):再写⼊2个元素,分别是2 & 3 — 被追加在1之后:如果两个元素被处理,那么是缓冲区中最⽼的两个元素被卸载。
在本例中,1 & 2被卸载,缓冲区中只剩下3:如果缓冲区中有7个元素,则是满的:如果缓冲区是满的,⼜要写⼊新的数据,⼀种策略是覆盖掉最⽼的数据。
此例中,2个新数据— A & B — 写⼊,覆盖了3 & 4:也可以采取其他策略,禁⽌覆盖缓冲区的数据,采取返回⼀个错误码或者抛出异常。
环形Buffer
![环形Buffer](https://img.taocdn.com/s3/m/22975f0d0622192e453610661ed9ad51f01d54fb.png)
环形Buffer环形Buffer[ 2009-4-16 16:00:00 | By: 箫笑 ]1推荐这些天用到了一个之前没用过的东西,环形Buffer。
感觉实在是个不错的东西。
它可以将接收(发送)数据与数据处理独立开来,适合于传输速度快,没有足够时间处理数据的情况,不至于数据丢失。
基本思路即是在内存里开辟一片区域,顺次往Buffer里写东西,一直写到最后那个内存(MAX_BUF_SIZE)时再将写入指针指向内存区的首地址,即接下来的数据转个环放到最开始处。
只有遇到Buffer里的有效存储空间为0时,才丢掉数据。
有效存储空间与MAX_BUF_SIZE的区别:有效存储空间是指那些没有存放数据,或者以前存放过,但已经处理过的数据,与MAX_BUF_SIZE是不同的。
可以用一个变量指示当前Buffer的使用状况,剩余多少空间可用。
具体实现主要使用以下几个变量:1. MAX_BUF_SIZE 缓冲区内存空间的最大量2. DataTp 有效数据的尾指针,指向最后写入的有效数据的下一个可用空间3. DataHp 有效数据的头指针,指向即将最先处理的那个有效数据4. DataCnt 有效数据的个数即当DataCnt等于MAX_BUF_SIZE时,缓冲区里已经不能再存储数据存储与取用完全独立,存储执行下面一系列操作:1. 判断DataCnt,看是否还有可用空间2. 将收到的数据放到DataTp指向的单元3. 将DataTp移到下一个单元4. DataCnt增加1取用执行下面的操作:1. 判断DataCnt,看是否有未处理的有效数据2. 读取DataHp指向单元的内容3. 将DataHp移到下一个单元4. DataCnt减1可以将存储,取用程序分别放在独立的地方,例如,中断接收,主程序循环取用。
例如串口接收程序如此实现:void UartHandler(void) interrupt 4{if(DataCnt< MAX_BUF_SIZE){UartRxBuf[DataTp] = SBUF;DataTp = (DataTp + 1) % MAX_BUF_SIZE;DataCnt++;}ReceiveTimer = 30;}%取模运算实现了指针环绕的目的,但是这个要占用比较长的时间,效率不高,网上有谈如何优化的,过会儿分析一下。
环形缓冲区C语言实现
![环形缓冲区C语言实现](https://img.taocdn.com/s3/m/018f74d6d4bbfd0a79563c1ec5da50e2524dd10e.png)
环形缓冲区C语言实现环形缓冲区1. 环形缓冲区的特性1、先进新出2、当缓冲区被使用完,且又有新的数据需要存储时,丢掉历史最久的数据,保存最新数据现实中的存储介质都是线性的,因此我们需要做一下处理,才能在功能上实现环形缓冲区算法说明:1、pHead和pTail分别是连续存储介质的首地址和尾地址2、pTail - pHead 的值是环形缓冲区的总长度3、pValid 是使用区域的起始指针,取数据时的起点,当取数据时pValid要发生偏移4、pValidTail 是使用区域的的结尾指针,存数据时的起点,当存数据时,pValidTail要发生偏移5、现有长度为addLen字节要存入,当pValidTail + addLen > pTail 时(超出了缓冲区,这时就要绕到开头pHead)int len1 = pTail - pValidTail;int len2 = addLen - len1;pValidTail = pHead + len2;//新的使用区的尾指针6、判断总长度是否变更,即是否有数据覆盖pValid所指向的区域,如果有,要偏移pValid下面是已验证的代码ringBuffer.c:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include "ringBuffer.h"#define BUFFER_SIZE 16 //缓冲区的长度,可以修改static u32 validLen;//已使用的数据长度static u8* pHead = NULL;//环形存储区的首地址static u8* pTail = NULL;//环形存储区的结尾地址static u8* pValid = NULL;//已使用的缓冲区的首地址static u8* pValidTail = NULL;//已使用的缓冲区的尾地址/** 初始化环形缓冲区* 环形缓冲区这里可以是malloc申请的内存,也可以是Flash存储介质* */void initRingbuffer(void){if(pHead == NULL){pHead = (u8*) malloc(BUFFER_SIZE);}pValid = pValidTail = pHead;pTail = pHead + BUFFER_SIZE;validLen = 0;}/** function:向缓冲区中写入数据* param:@buffer 写入的数据指针* @addLen 写入的数据长度* return:-1:写入长度过大* -2:缓冲区没有初始化* */int wirteRingbuffer(u8* buffer,u32 addLen){if(addLen > BUFFER_SIZE) return -2;if(pHead==NULL) return -1;assert(buffer);//将要存入的数据copy到pValidTail处if(pValidTail + addLen > pTail)//需要分成两段copy{int len1 = pTail - pValidTail;int len2 = addLen - len1;memcpy( pValidTail, buffer, len1);memcpy( pHead, buffer + len1, len2);pValidTail = pHead + len2;//新的有效数据区结尾指针}else{memcpy( pValidTail, buffer, addLen);pValidTail += addLen;//新的有效数据区结尾指针}//需重新计算已使用区的起始位置if(validLen + addLen > BUFFER_SIZE){int moveLen = validLen + addLen - BUFFER_SIZE;//有效指针将要移动的长度 if(pValid + moveLen > pTail)//需要分成两段计算{int len1 = pTail - pValid;int len2 = moveLen - len1;pValid = pHead + len2;}else{pValid = pValid + moveLen;}validLen = BUFFER_SIZE;}else{validLen += addLen;}return 0;}/** function:从缓冲区内取出数据* param :@buffer:接受读取数据的buffer* @len:将要读取的数据的长度* return :-1:没有初始化* >0:实际读取的长度* */int readRingbuffer(u8* buffer,u32 len){if(pHead==NULL) return -1;assert(buffer);if(validLen ==0) return 0;if( len > validLen) len = validLen;if(pValid + len > pTail)//需要分成两段copy{int len1 = pTail - pValid;int len2 = len - len1;memcpy( buffer, pValid, len1);//第一段memcpy( buffer+len1, pHead, len2);//第二段,绕到整个存储区的开头pValid = pHead + len2;//更新已使用缓冲区的起始}else{memcpy( buffer, pValid, len);pValid = pValid +len;//更新已使用缓冲区的起始}validLen -= len;//更新已使用缓冲区的长度return len;}/** function:获取已使用缓冲区的长度* return :已使用的buffer长度* */u32 getRingbufferValidLen(void){return validLen;}/** function:释放环形缓冲区* */void releaseRingbuffer(void){if(pHead!=NULL) free(pHead);pHead = NULL;}ringBuffer.h#ifndef RINGBUFFER_H_#define RINGBUFFER_H_typedef unsigned char u8;typedef unsigned int u32;void initRingbuffer(void);int wirteRingbuffer(u8* buffer,u32 len);int readRingbuffer(u8* buffer,u32 len);u32 getRingbufferValidLen(void);void releaseRingbuffer(void);#endif /* RINGBUFFER_H_ */广告:本人在上海开有C语言培训班和承接单片机项目,如有需要请联系测试 main 函数#include <stdio.h>#include <stdlib.h>#include "ringBuffer.h"// 主函数int main(){char c;int readLen;u8 readBuffer[10];//setvbuf(stdout,NULL,_IONBF,0); //pinrtf、putchar不能立马输出,打开此注释 initRingbuffer();printf("Please enter a line [blank line to terminate]> ");do{c=getchar();putchar(c);switch(c){case 'Q':goto exit;break;case 'R':readLen = readRingbuffer(readBuffer,10);printf("readRingbuffer len:%d\n",readLen);if(readLen > 0){printf("readRingbuffer:");for(int i=0;i<readLen;i++){printf("%c ",(char)readBuffer[i]);}printf("\n");}break;default :if(c!='\n') wirteRingbuffer((u8*)&c,1);break;}}while (1);exit:releaseRingbuffer();printf("exit.\n");return 0;}**注意:请尊重原创者的辛劳,转载请注明。
环形缓冲区
![环形缓冲区](https://img.taocdn.com/s3/m/4baa2ab81a37f111f1855bc2.png)
环形缓冲区该写操作的分析与实现环形缓冲区是嵌人式系统中一种重要的常用数据结构.在多任务环境下实时,如果有多个读写任务.一般需要用信号量来保护多个任务共享的环形缓冲区。
但是如果只存在1个读任务和1个写任务,采取适当的措施可以避免使用信号量,从而提高程序的执行效率,并且避免任务间竟争所造成的不一致性。
1 单线程下的实现先定义一个简单的环形缓冲区数据结构;基于这样一个条件,当环形缓冲区满时,不能再往里写数据了。
struct ringbuf{uin t8 bu f[m axlen];uin t8 r ptr ;uin t8 wp lr;数据元素是无符号8位整数,maxlen代表环形缓冲区的最大长度,rptr为读指针,wptr为写指针。
读写指针初始化为rptr=wptr=0·1.1 读操作的实现BOOL readbuf(structringbuf "mybufuint8'readdata)I/队列为空if(m y bu f一>rptr= =m ybuf-> wptr)ret um F AL S E;els e[刀队列里有数据,读出来're ad dat a= rrty buf->buf[mybuf->印tr];my bu f-> rp tr + +;/调整读指针,以防止读指针越界my bu f-> rp tr- m ybuf->rptr./ m axlen;ret unr T R UE ;}}该函数在缓冲区为空时返回FALSE。
在缓冲区有数据时,1次读1个敌据元素,存放在readdata所指向的变量里,并返回TRUE.2 写操作的实现BOOL writebuf(structri ngbuf" mybufu int8w ritedata)]/队列为满if(m y bu f->rpt--=((mybuf->wptr+l)0lomaxlen))ret unr F A LS E;els e]/队列有空位置,写数据my bu f-> bu f[m ybuf->wptr]=writedata;my bu f-> w ptr + +;/调整写指针,以防止写指针越界my bu f-> wp tr- m ybuf->wptr%maxlen;ret ur nT R U E;}}在判断缓冲区是否满的条件中.之所以要摸maxlen,是因为假设读写指针为图1所示,wptr所指的位置为空。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
printf(“Buffer is empty\n”); return 0.0; } /* 向环形缓冲区中放入一个元素*/ void put(double z) { if (n<NMAX){ buffer[iput]=z; iput = addring(iput); n++; } else printf(“Buffer is full\n”); } int main{void) { chat opera[5]; double z; do { printf(“Please input p|g|e?”); scanf(“%s”, &opera); switch(tolower(opera[0])){ case ‘p’: /* put */ printf(“Please input a float number?”);
到项目的针对性简单性,实现了一个简单的环形缓冲队列,比 STL 的 vector 简单 PS: 第一次使用模板,原来类模板的定义要放在.h 文件中, 不然会出现连接错误。 template <class _Type> class CShareQueue { public: CShareQueue(); CShareQueue(unsigned int bufsize); virtual ~CShareQueue(); _Type pop_front(); bool push_back( _Type item); //返回容量 unsigned int capacity() { //warning:需要外部数据一致性 return m_capacity; } //返回当前个数 unsigned int size() { //warning:需要外部数据一致性 return m_size; } //是否满//warning: 需要外部控制数据一致性 bool IsFull() { return (m_size >= m_capacity); } bool IsEmpty() { return (m_size == 0); }
pBuf = new _Type[512];//默认 512 m_capacity = 512; } template <class _Type> CShareQueue<_Type>::CShareQueue(unsigned int bufsize) : m_head(0), m_tail(0) { if( bufsize > 512 || bufsize < 1) { pBuf = new _Type[512]; m_capacity = 512; } else { pBuf = new _Type[bufsize]; m_capacity = bufsize; } } template <class _Type> CShareQueue<_Type>::~CShareQueue() { delete[] pBuf; pBuf = NULL; m_head = m_tail = m_size = m_capacity = 0; } //前面弹出一个元素 template <class _Type> _Type CShareQueue<_Type>::pop_front() { if( IsEmpty() ) { return NULL; } _Type itemtmp; itemtmp = pBuf[m_head]; m_head = (m_head + 1) % m_capacity; --m_size; return itemtmp; } //从尾部加入队列 template <class _Type>
scanf(“%lf”, &z); put(z); break; case ‘g’: /* get */ z = get(); printf(“%8.2f from Buffer\n”, z); break; case ‘e’: printf(“End\n”); break; default: printf(“%s - Operation command error! \n”, opera); }/* end switch */ }while(opera[0] != ’e’); return 0; } 在 CAN 通信卡设备驱动程序中,为了增强 CAN 通信卡的通信能力、提高通信效率,根据 CAN 的特点,使 用两级缓冲区结构,即直接面向 CAN 通信卡的收发缓 冲区和直接面向系统调用的接收帧缓冲区。 通讯中 的收发缓冲区一般采用环形队列(或称为 FIFO 队列),使用环形的缓冲区可以使得读写并发执行,读进程 和写进程可以采用“生产者和消费者”的模型来 访问缓冲区,从而方便了缓存的使用和管理。然而,环形缓 冲区的执行效率并不高,每读一个字节之前,需要判断缓冲区是否为空,并且移动尾指针时需要进行“折行 处理”(即当指针指到缓冲区内存的末尾时,需要新将其定向到缓冲区的首地址);每写一个字节之前,需 要判断缓区是否为,并且移动尾指针时同样需要进行“ 折行处理”。程序大部分的执行过程都是在处理个别 极端的情况。只有小部分在进行实际有效的操作。这就是软件工程中所谓的“8 比 2”关系。结合 CAN 通讯 实际情况,在本设计中对环形队列进行了改进,可以较大地提高数据的收发效率。 由于 CAN 通信卡上接 收和发送缓冲器每次只接收一帧 CAN 数据,而且根据 CAN 的通讯协议,CAN 控制器的发送数据由 1 个字 节的标识符、一个字节的 RTR 和 DLC 位及 8 个字节的数据区组成,共 10 个字节;接收缓冲器与之类似, 也有 10 个字节的寄存器。所以 CAN 控制器收的数据是短小的定长帧(数据可以不满 8 字节)。 于是, 采用度为 10 字节的数据块业分配内存比较方便,即每次需要内存缓冲区时,直接分配 10 个字节,由于这 10 个字节的地址是线性的,故不需要进行“折行”处理。更重要的是,在向缓冲区中写数据时,只需要判断
一次是否有空闲块并获取其块首指针就可以了,从而减少了重复性的条件判断,大大提高了程序的执行效 率;同样在从缓冲队列中读取数据时,也是一次读取 10 字节的数据块,同样减少了重复性的条件判断。 在 CAN 卡驱动程序中采用如下所示的称为“Block_Ring_t”的数据结构作为收发数据的缓冲区: typedef struct { long signature; unsigned char *head_p; unsigned char *tail_p; unsigned char *begin_p; unsigned char *end_p; unsigned char buffer [BLOCK_RING_BUFFER_SIZE]; int usedbytes; }Block_Ring_t; 该数据结构在通用的环形队列上增加了一个数据成员 usedbytes,它表示当前缓冲区中有多少字节的空间 被占用了。使用 usedbytes,可以比较方 便地进行缓冲区满或空的判断。当 usedbytes=0 时,缓冲区空; 当 usedbytes=BLOCK_RING_BUFFER_SIZE 时,缓冲区 满。 本驱动程序除了收发缓冲区外,还有一个接 收帧缓冲区,接收帧队列负责管理经 Hilon A 协议解包后得到的数据帧。由于有可能要同接收多个数据帧, 而根据 CAN 总线遥通信协议,高优先级的报文将抢占总线,则有可能在接收一个低优先级且被分为 好几 段发送的数据帧时,被一个优先级高的数据帧打断。这样会出现同时接收到多个数据帧中的数据包,因而 需要有个接收队列对同时接收的数据帧进行管理。 当有新的数据包到来时,应根据 addr(通讯地址),mo de(通讯方式),index(数据包的序号)来判断是否是新的数据帧。如果是,则开辟新的 frame_node; 否则如果已有相应的帧节点存地,则将数据附加到该帧的末尾;在插入数据的同时,应该检查接收包的序 号是否正确,如不正确将丢弃这包 数据。 每次建立新的 frame_node 时,需要向 frame_queue 申请内存 空间;当 frame_queue 已满时,释放掉队首的节点(最早接收的但未完 成的帧)并返回该节点的指针。 当系统调用读取了接收帧后,释放该节点空间,使设备驱动程序可以重新使用该节点。 形缓冲区:环形缓冲队列学习 来源: 发布时间:星期四, 2008 年 9 月 25 日 浏览:117 次 评论:0 项目中需要线程之间共享一个缓冲 FIFO 队列,一个线程往队列中添数据,另一个线程取数据(经典的生产 者-消费者问题)。开始考虑用 STL 的 vector 容器, 但不需要随机访问,频繁的删除最前的元素引起内存 移动,降低了效率。使用 LinkList 做队列的话,也需要频繁分配和释放结点内存。于是自己实现一个有 限 大小的 FIFO 队列,直接采用数组进行环形读取。 队列的读写需要在外部进程线程同步(另外写了一个 RWGuard 类, 见另一文)
个
数
据
。
2、实例:环形缓冲区的实现 环形缓冲区是数据通信程序中使用最为广泛的数据结构之一,下面的代码,实现了一个环形缓冲区: /*ringbuf .c*/ #include<stdio. h>
#include<ctype. h> #define NMAX 8 int iput = 0; /* 环形缓冲区的当前放入位置 */ int iget = 0; /* 缓冲区的当前取出位置 */ int n = 0; /* 环形缓冲区中的元素总数量 */ double buffer[NMAX]; /* 环形缓冲区的地址编号计算函数,如果到达唤醒缓冲区的尾部,将绕回到头部。 环形缓冲区的有效地址编号为:0 到(NMAX-1) */ int addring (int i) { return (i+1) == NMAX ? 0 : i+1; } /* 从环形缓冲区中取一个元素 */ double get(void) { int pos; if (n>0){ Pos = iget; iget = addring(iget); n--; return buffer[pos]; } else {