fbpx
Wikipedia

Buffer circular

Un buffer circular, buffer cíclico o buffer de anillo es una estructura de datos que utiliza un buffer único o array ordinario y que adopta su nombre por la forma en que se ponen o sacan sus elementos. Estos buffers son de tamaño fijo, internamente es como si estuviera conectado de extremo a extremo.

Un anillo mostrando, conceptualmente, un buffer circular. El esquema muestra claramente que el buffer no tiene final, y se puede mover alrededor de todo el buffer. Sin embargo, como la memoria nunca puede ser creada físicamente como un anillo, se usa generalmente una representación lineal.

Usos

Un ejemplo de uso de un buffer circular de escritura puede ser en multimedia. Si este tipo de buffer es usado como un buffer delimitador en el problema del productor-consumidor, es probablemente deseado por el productor (por ejemplo, un generador de audio) sobrescribir los datos antiguos si el consumidor (como ser la tarjeta de audio) no está momentáneamente disponible para un mantenimiento. Otro ejemplo es el método de síntesis de guías de ondas digitales, el cual usa buffers circulares para simular de forma eficiente el sonido de la vibración de los instrumentos de cuerda o viento. El atributo preciado de los buffers circulares es que no se tiene la necesidad de mover los elementos por la cola en el momento de que uno de ellos es consumido. Por otra parte, si se usara un buffer no circular sería necesario modificar todos los elementos cuando uno sea consumido. En otras palabras, el buffer circular es bien visto como un buffer FIFO (primero en entrar es el primero en salir); mientras que un buffer no circular representaría un buffer LIFO (último en entrar es el primero en salir). Una buena estrategia de implementación para una cola con tamaño máximo es mediante el uso de buffers circulares; en este caso todas las operaciones de la cola se realizan en tiempo constante. Sin embargo, expandir un buffer circular requiere cambio de memoria, lo cual es costoso.

¿Cómo funciona?

Un buffer circular trabaja básicamente con dos índices para acceder a los elementos del buffer, que aquí llamaremos Inpointer y Outpointer. Ambos índices tienen avance incremental y cíclico, es decir, se incrementan de uno en uno y luego de apuntar al último elemento del buffer vuelven a apuntar al primero.

Al inicio los dos índices apuntan al primer elemento del buffer. Veamos cómo y cuándo se incrementan:

  • Cada nuevo dato a guardar en el buffer será depositado en la casilla actualmente apuntada por Inpointer. A continuación Inpointer se incrementa en uno.
  • Por otro lado, cada dato que salga del buffer será el de la casilla actualmente apuntada por Outpointer. A continuación Outpointer se incremente en uno.

Estos buffers tienen un comportamiento FIFO ("First In - First Out", "Primero en entrar - primero en salir").

Una consecuencia de la memoria intermedia circular es que cuando está lleno y se realiza la posterior escritura, entonces comienza a sobrescribir los datos más antiguos.

Para saber si en el buffer hay espacio para meter más datos o si hay al menos un dato para sacar, se debe usar la diferencia entre las posiciones de los punteros. Otra posible opción es utilizar una variable adicional que se incremente con cada dato ingresado y se decremente con cada dato extraído.

Un buffer circular comienza vacío y con un tamaño predefinido. Por ejemplo, este es un buffer de 7 elementos:

 

Asuma que un 1 es escrito en el medio del buffer (la locación exacta no importa en un buffer circular):

 

Luego, asuma que dos elementos más son añadidos — 2 & 3 — los cuales quedan añadidos después del 1:

 

Si dos elementos son eliminados del buffer, los valores más viejos dentro del buffer son borrados. Los dos elementos borrados, en este caso, son 1 & 2; quedando el buffer con solamente un 3:

 

Si el buffer tiene 7 elementos se encuentra lleno:

 

Una consecuencia de los buffers circulares es que cuando se encuentra lleno y se realiza una nueva escritura, se comienza a sobrescribir los datos antiguos. En este caso, se agregan dos elementos más — A & B — y sobrescriben el 3 & 4:

 

Como una alternativa, se puede hace que las rutinas que administran el buffer no permitan que los datos se sobrescriban y retornen un error o una excepción.

Finalmente, si dos elementos son borrados ahora, se va a retornar 5 & 6 y no 3 & 4, dado que A & B sobrescribió el 3 & 4:

 

Mecánica del buffer circular

Punteros de Inicio/Fin

Generalmente, un buffer circular requiere tres punteros:

  • uno para el buffer que está actualmente en memoria
  • uno para apuntar el comienzo de los datos válidos
  • y otro que apunte al final de los datos válidos.

Como alternativa para lenguajes que no soportan punteros, se puede utilizar un buffer de tamaño fijo, con dos enteros que contengan los índices de comienzo y fin de los datos válidos.

Existen varias maneras de etiquetar los punteros y la semántica puede variar; una manera de hacerlo es la siguiente:

Esta imagen muestra un buffer parcialmente lleno:

 

Esta imagen muestra un buffer completo con dos elementos que han sido sobrescritos:

 

Una nota sobre la segunda imagen es que después de que cada elemento es sobrescrito el puntero de comienzo es incrementado también.

¿Qué dificultades presenta?

Un buffer circular puede presentar ciertos problemas que hay que saber controlar. En concreto las situaciones problemáticas si no son controladas son en el caso de que el buffer se encuentre totalmente vacío o totalmente lleno, en estos casos el índice de escritura coincidirá con el de lectura, lo que provocará fallos tales como que se lea información incorrecta del buffer o que se escriba información destruyendo información útil del buffer, provocando que ésta no pueda ser leída.

Posibles métodos para controlar estos problemas:

  • Dejar una posición como mínimo entre los índices de escritura y lectura.
  • Utilizar un contador de llenado del buffer.
  • Utilizar dos contadores uno de lecturas y otro de escrituras.

Dejar una posición como mínimo entre los índices de escritura y lectura.

Este método consiste en permitir realizar escrituras en el buffer hasta que el índice de escritura llegue a la posición anterior del índice de lectura, lo mismo ocurre para la operación de lectura.

Las Ventajas son:

  • Simple y robusto.
  • Solo necesitas los dos punteros.

Las desventajas son:

  • Nunca se puede usar el buffer entero.
  • Solo está permitido acceder a un elemento por vez, dado que no se puede saber fácilmente cuantos elementos hay al lado de cada uno en memoria.

Un ejemplo de implementación en C: (Mantiene una ranura abierta)

#include <stdio.h> #include <string.h> #include <malloc.h> /*!  * Circular Buffer Example (Keep one slot open)  * Compile: gcc cbuf.c -o cbuf.exe  */ /**< Tamaño de buffer */ #define BUFFER_SIZE 10 #define NUM_OF_ELEMS (BUFFER_SIZE-1) /**< Tipos de buffer circular */ typedef unsigned char INT8U; typedef INT8U KeyType; typedef struct { INT8U writePointer; /**< puntero de escritura */ INT8U readPointer; /**< puntero de lectura */ INT8U size; /**< tamaño del buffer circular */ KeyType keys[0]; /**< elemento del buffer circular */ } CircularBuffer; /**< Inicialización del buffer circular */ CircularBuffer* CircularBufferInit(CircularBuffer** pQue, int size) { int sz = size*sizeof(KeyType)+sizeof(CircularBuffer); *pQue = (CircularBuffer*) malloc(sz); if(*pQue) { printf("Init CircularBuffer: keys[%d] (%d)\n", size, sz); (*pQue)->size=size; (*pQue)->writePointer = 0; (*pQue)->readPointer = 0; } return *pQue; } inline int CircularBufferIsFull(CircularBuffer* que) { return (((que->writePointer + 1) % que->size) == que->readPointer); } inline int CircularBufferIsEmpty(CircularBuffer* que) { return (que->readPointer == que->writePointer); } inline int CircularBufferEnque(CircularBuffer* que, KeyType k) { int isFull = CircularBufferIsFull(que); if(!isFull) { que->keys[que->writePointer] = k; que->writePointer++; que->writePointer %= que->size; } return isFull; } inline int CircularBufferDeque(CircularBuffer* que, KeyType* pK) { int isEmpty = CircularBufferIsEmpty(que); if(!isEmpty) { *pK = que->keys[que->readPointer]; que->readPointer++; que->readPointer %= que->size; } return(isEmpty); } inline int CircularBufferPrint(CircularBuffer* que) { int i=0; int isEmpty = CircularBufferIsEmpty(que); int isFull = CircularBufferIsFull(que); printf("\n==Q: w:%d r:%d f:%d e:%d\n", que->writePointer, que->readPointer, isFull, isEmpty); for(i=0; i< que->size; i++) { printf("%d ", que->keys[i]); } printf("\n"); return(isEmpty); } int main(int argc, char *argv[]) { CircularBuffer* que; KeyType a = 101; int isEmpty, i; CircularBufferInit(&que, BUFFER_SIZE); CircularBufferPrint(que); for(i=1; i<=3; i++) { a=10*i; printf("\n\n===\nTest: Insert %d-%d\n", a, a+NUM_OF_ELEMS-1); while(! CircularBufferEnque(que, a++)); //CircularBufferPrint(que); printf("\nRX%d:", i); a=0; isEmpty = CircularBufferDeque(que, &a); while (!isEmpty) {  printf("%02d ", a);  a=0;  isEmpty = CircularBufferDeque(que, &a); } //CircularBufferPrint(que); } free(que); return 0; } 

Un ejemplo de implementación en C: (Usando todas las ranuras)

#include <stdio.h> #include <string.h> #include <malloc.h> /*!  * Circular Buffer Example  * Compile: gcc cbuf.c -o cbuf.exe  */ /**< Buffer Size */ #define BUFFER_SIZE 16 /**< Tipos de buffer circular */ typedef unsigned char INT8U; typedef INT8U KeyType; typedef struct { INT8U writePointer; /**< Puntero escritura*/ INT8U readPointer; /**< Puntero lectura */ INT8U size; /**< tamaño del buffer circular */ KeyType keys[0]; /**< Elemento del buffer circular */ } CircularBuffer; /**< Inicialización del buffer circular */ CircularBuffer* CircularBufferInit(CircularBuffer** pQue, int size) { int sz = size*sizeof(KeyType)+sizeof(CircularBuffer); *pQue = (CircularBuffer*) malloc(sz); if(*pQue) {  printf("Init CircularBuffer: keys[%d] (%d)\n", size, sz);  (*pQue)->size=size;  (*pQue)->writePointer = 0;  (*pQue)->readPointer = 0; } return *pQue; } inline int CircularBufferIsFull(CircularBuffer* que) { return ((que->writePointer + 1) % que->size == que->readPointer); } inline int CircularBufferIsEmpty(CircularBuffer* que) { return ((que->readPointer == que->writePointer); } inline int CircularBufferEnque(CircularBuffer* que, KeyType k) { int isFull = CircularBufferIsFull(que); que->keys[que->writePointer] = k; que->writePointer++; que->writePointer %= que->size; return isFull; } inline int CircularBufferDeque(CircularBuffer* que, KeyType* pK) { int isEmpty = CircularBufferIsEmpty(que); *pK = que->keys[que->readPointer]; que->readPointer++; que->readPointer %= que->size; return(isEmpty); } int main(int argc, char *argv[]) { CircularBuffer* que; KeyType a = 0; int isEmpty; CircularBufferInit(&que, BUFFER_SIZE); while(! CircularBufferEnque(que, a++)); do {  isEmpty = CircularBufferDeque(que, &a);  printf("%02d ", a); } while (!isEmpty); printf("\n"); free(que); return 0; } 

Utilizar un contador de llenado del buffer.

Esta técnica consiste en mantener un contador de llenado que se incrementa con cada operación de escritura y se decrementa en cada operación de lectura, esto permite conocer en todo momento el estado de uso del buffer, dándonos la posibilidad de no permitir la lectura si el contador de llenado esta a cero y de no permitir la escritura si el contador de llenado esta en el valor de máxima capacidad del buffer.

Utilizar dos contadores uno de lecturas y otro de escrituras.

Este método consiste en utilizar dos contadores, uno para lectura y otro para escritura, dichos contadores se iran incrementando por cada operación correspondiente, de forma que cuando realizamos una escritura aumenta el contador de escritura y similar para el contador de lectura. Manteniendo este sistema, podemos comprobar el estado en el que se encuentra el buffer en cualquier momento.

POR EJEMPLO: el buffer podría estar en los siguientes estados:

  • vacío: el contador de escritura y lectura coinciden.
  • saturado: el contador de lectura es mayor que el de escritura o bien el contador de escritura es mayor que el de lectura más la capacidad máxima del buffer.
  • lleno: el contador de escritura es igual que el contador de lectura más la capacidad máxima del buffer.

Optimización

Una implementación del buffer circular puede ser optimizada asignando al buffer dos regiones contiguas de memoria virtual. (Naturalmente, el tamaño del buffer debe ser múltiplo del tamaño de página del sistema.) La lectura y escritura en el buffer circular debe realizarse con gran eficiencia en cuanto al acceso directo a memoria.

Ejemplo de implementación POSIX

#include <sys/mman.h> #include <stdlib.h> #include <unistd.h> #define report_exceptional_condition() abort () struct ring_buffer { void *address; unsigned long count_bytes; unsigned long write_offset_bytes; unsigned long read_offset_bytes; }; //Warning order should be at least 12 for Linux void ring_buffer_create (struct ring_buffer *buffer, unsigned long order) { char path[] = "/dev/shm/ring-buffer-XXXXXX"; int file_descriptor; void *address; int status; file_descriptor = mkstemp (path); if (file_descriptor < 0) report_exceptional_condition (); status = unlink (path); if (status) report_exceptional_condition (); buffer->count_bytes = 1UL << order; buffer->write_offset_bytes = 0; buffer->read_offset_bytes = 0; status = ftruncate (file_descriptor, buffer->count_bytes); if (status) report_exceptional_condition (); buffer->address = mmap (NULL, buffer->count_bytes << 1, PROT_NONE,   MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (buffer->address == MAP_FAILED) report_exceptional_condition (); address = mmap (buffer->address, buffer->count_bytes, PROT_READ | PROT_WRITE,  MAP_FIXED | MAP_SHARED, file_descriptor, 0); if (address != buffer->address) report_exceptional_condition (); address = mmap (buffer->address + buffer->count_bytes,  buffer->count_bytes, PROT_READ | PROT_WRITE,  MAP_FIXED | MAP_SHARED, file_descriptor, 0); if (address != buffer->address + buffer->count_bytes) report_exceptional_condition (); status = close (file_descriptor); if (status) report_exceptional_condition (); } void ring_buffer_free (struct ring_buffer *buffer) { int status; status = munmap (buffer->address, buffer->count_bytes << 1); if (status) report_exceptional_condition (); } void * ring_buffer_write_address (struct ring_buffer *buffer) { /*** void pointer arithmetic is a constraint violation. ***/ return buffer->address + buffer->write_offset_bytes; } void ring_buffer_write_advance (struct ring_buffer *buffer,   unsigned long count_bytes) { buffer->write_offset_bytes += count_bytes; } void * ring_buffer_read_address (struct ring_buffer *buffer) { return buffer->address + buffer->read_offset_bytes; } void ring_buffer_read_advance (struct ring_buffer *buffer,   unsigned long count_bytes) { buffer->read_offset_bytes += count_bytes; if (buffer->read_offset_bytes >= buffer->count_bytes) { buffer->read_offset_bytes -= buffer->count_bytes; buffer->write_offset_bytes -= buffer->count_bytes; } } unsigned long ring_buffer_count_bytes (struct ring_buffer *buffer) { return buffer->write_offset_bytes - buffer->read_offset_bytes; } unsigned long ring_buffer_count_free_bytes (struct ring_buffer *buffer) { return buffer->count_bytes - ring_buffer_count_bytes (buffer); } void ring_buffer_clear (struct ring_buffer *buffer) { buffer->write_offset_bytes = 0; buffer->read_offset_bytes = 0; } 
//--------------------------------------------------------------------------- // template class Queue //--------------------------------------------------------------------------- template <class T> class Queue { T *qbuf; // buffer data int qsize; //  int head; // index begin data int tail; // index stop data inline void Free() {  if (qbuf != 0)  {   delete []qbuf;   qbuf= 0;  }  qsize= 1;  head= tail= 0; } public: Queue() {  qsize= 32;  qbuf= new T[qsize];  head= tail= 0; } Queue(const int size): qsize(1), qbuf(0), head(0), tail(0) {  if ((size <= 0) || (size & (size - 1)))  {   throw "Value is not degree of two";  }  qsize= size;  qbuf= new T[qsize];  head= tail= 0; } ~Queue() {  Free(); } void Enqueue(const T &p) {  if (IsFull())  {   throw "Queue is full";  }  qbuf[tail]= p;  tail= (tail + 1) & (qsize - 1); } // Retrieve the item from the queue void Dequeue(T &p) {  if (IsEmpty())  {   throw "Queue is empty";  }  p= qbuf[head];  head= (head + 1) & (qsize - 1); } // Get i-element with not delete void Peek(const int i, T &p) const {  int j= 0;  int k= head;  while (k != tail)  {   if (j == i) break;   j++;   k= (k + 1) & (qsize - 1);  }  if (k == tail) throw "Out of range";  p= qbuf[k]; } // Size must by: 1, 2, 4, 8, 16, 32, 64, .. void Resize(const int size) {  if ((size <= 0) || (size & (size - 1)))  {   throw "Value is not degree of two";  }  Free();  qsize= size;  qbuf= new T[qsize];  head= tail= 0; } inline void Clear(void) { head= tail= 0; } inline int GetCapacity(void) const { return (qsize - 1); } // Count elements inline int GetBusy(void) const { return ((head > tail) ? qsize : 0) + tail - head; } // true - if queue if empty inline bool IsEmpty(void) const { return (head == tail); } // true - if queue if full inline bool IsFull(void) const { return ( ((tail + 1) & (qsize - 1)) == head ); } }; //--------------------------------------------------------------------------- // Use: Queue <int> Q; Q.Enqueue(5); Q.Enqueue(100); Q.Enqueue(13); int len= Q.GetBusy(); int val; Q.Dequeue(val); //--------------------------------------------------------------------------- 
  •   Datos: Q1224994
  •   Multimedia: Category:Circular buffers

buffer, circular, este, artículo, sección, necesita, referencias, aparezcan, publicación, acreditada, este, aviso, puesto, junio, 2012, buffer, circular, buffer, cíclico, buffer, anillo, estructura, datos, utiliza, buffer, único, array, ordinario, adopta, nomb. Este articulo o seccion necesita referencias que aparezcan en una publicacion acreditada Este aviso fue puesto el 3 de junio de 2012 Un buffer circular buffer ciclico o buffer de anillo es una estructura de datos que utiliza un buffer unico o array ordinario y que adopta su nombre por la forma en que se ponen o sacan sus elementos Estos buffers son de tamano fijo internamente es como si estuviera conectado de extremo a extremo Un anillo mostrando conceptualmente un buffer circular El esquema muestra claramente que el buffer no tiene final y se puede mover alrededor de todo el buffer Sin embargo como la memoria nunca puede ser creada fisicamente como un anillo se usa generalmente una representacion lineal Indice 1 Usos 2 Como funciona 3 Mecanica del buffer circular 3 1 Punteros de Inicio Fin 4 Que dificultades presenta 4 1 Dejar una posicion como minimo entre los indices de escritura y lectura 4 2 Utilizar un contador de llenado del buffer 4 3 Utilizar dos contadores uno de lecturas y otro de escrituras 5 Optimizacion 5 1 Ejemplo de implementacion POSIXUsos EditarUn ejemplo de uso de un buffer circular de escritura puede ser en multimedia Si este tipo de buffer es usado como un buffer delimitador en el problema del productor consumidor es probablemente deseado por el productor por ejemplo un generador de audio sobrescribir los datos antiguos si el consumidor como ser la tarjeta de audio no esta momentaneamente disponible para un mantenimiento Otro ejemplo es el metodo de sintesis de guias de ondas digitales el cual usa buffers circulares para simular de forma eficiente el sonido de la vibracion de los instrumentos de cuerda o viento El atributo preciado de los buffers circulares es que no se tiene la necesidad de mover los elementos por la cola en el momento de que uno de ellos es consumido Por otra parte si se usara un buffer no circular seria necesario modificar todos los elementos cuando uno sea consumido En otras palabras el buffer circular es bien visto como un buffer FIFO primero en entrar es el primero en salir mientras que un buffer no circular representaria un buffer LIFO ultimo en entrar es el primero en salir Una buena estrategia de implementacion para una cola con tamano maximo es mediante el uso de buffers circulares en este caso todas las operaciones de la cola se realizan en tiempo constante Sin embargo expandir un buffer circular requiere cambio de memoria lo cual es costoso Como funciona EditarUn buffer circular trabaja basicamente con dos indices para acceder a los elementos del buffer que aqui llamaremos Inpointer y Outpointer Ambos indices tienen avance incremental y ciclico es decir se incrementan de uno en uno y luego de apuntar al ultimo elemento del buffer vuelven a apuntar al primero Al inicio los dos indices apuntan al primer elemento del buffer Veamos como y cuando se incrementan Cada nuevo dato a guardar en el buffer sera depositado en la casilla actualmente apuntada por Inpointer A continuacion Inpointer se incrementa en uno Por otro lado cada dato que salga del buffer sera el de la casilla actualmente apuntada por Outpointer A continuacion Outpointer se incremente en uno Estos buffers tienen un comportamiento FIFO First In First Out Primero en entrar primero en salir Una consecuencia de la memoria intermedia circular es que cuando esta lleno y se realiza la posterior escritura entonces comienza a sobrescribir los datos mas antiguos Para saber si en el buffer hay espacio para meter mas datos o si hay al menos un dato para sacar se debe usar la diferencia entre las posiciones de los punteros Otra posible opcion es utilizar una variable adicional que se incremente con cada dato ingresado y se decremente con cada dato extraido Un buffer circular comienza vacio y con un tamano predefinido Por ejemplo este es un buffer de 7 elementos Asuma que un 1 es escrito en el medio del buffer la locacion exacta no importa en un buffer circular Luego asuma que dos elementos mas son anadidos 2 amp 3 los cuales quedan anadidos despues del 1 Si dos elementos son eliminados del buffer los valores mas viejos dentro del buffer son borrados Los dos elementos borrados en este caso son 1 amp 2 quedando el buffer con solamente un 3 Si el buffer tiene 7 elementos se encuentra lleno Una consecuencia de los buffers circulares es que cuando se encuentra lleno y se realiza una nueva escritura se comienza a sobrescribir los datos antiguos En este caso se agregan dos elementos mas A amp B y sobrescriben el 3 amp 4 Como una alternativa se puede hace que las rutinas que administran el buffer no permitan que los datos se sobrescriban y retornen un error o una excepcion Finalmente si dos elementos son borrados ahora se va a retornar 5 amp 6 y no 3 amp 4 dado que A amp B sobrescribio el 3 amp 4 Mecanica del buffer circular EditarPunteros de Inicio Fin Editar Generalmente un buffer circular requiere tres punteros uno para el buffer que esta actualmente en memoria uno para apuntar el comienzo de los datos validos y otro que apunte al final de los datos validos Como alternativa para lenguajes que no soportan punteros se puede utilizar un buffer de tamano fijo con dos enteros que contengan los indices de comienzo y fin de los datos validos Existen varias maneras de etiquetar los punteros y la semantica puede variar una manera de hacerlo es la siguiente Esta imagen muestra un buffer parcialmente lleno Esta imagen muestra un buffer completo con dos elementos que han sido sobrescritos Una nota sobre la segunda imagen es que despues de que cada elemento es sobrescrito el puntero de comienzo es incrementado tambien Que dificultades presenta EditarUn buffer circular puede presentar ciertos problemas que hay que saber controlar En concreto las situaciones problematicas si no son controladas son en el caso de que el buffer se encuentre totalmente vacio o totalmente lleno en estos casos el indice de escritura coincidira con el de lectura lo que provocara fallos tales como que se lea informacion incorrecta del buffer o que se escriba informacion destruyendo informacion util del buffer provocando que esta no pueda ser leida Posibles metodos para controlar estos problemas Dejar una posicion como minimo entre los indices de escritura y lectura Utilizar un contador de llenado del buffer Utilizar dos contadores uno de lecturas y otro de escrituras Dejar una posicion como minimo entre los indices de escritura y lectura Editar Este metodo consiste en permitir realizar escrituras en el buffer hasta que el indice de escritura llegue a la posicion anterior del indice de lectura lo mismo ocurre para la operacion de lectura Las Ventajas son Simple y robusto Solo necesitas los dos punteros Las desventajas son Nunca se puede usar el buffer entero Solo esta permitido acceder a un elemento por vez dado que no se puede saber facilmente cuantos elementos hay al lado de cada uno en memoria Un ejemplo de implementacion en C Mantiene una ranura abierta include lt stdio h gt include lt string h gt include lt malloc h gt Circular Buffer Example Keep one slot open Compile gcc cbuf c o cbuf exe lt Tamano de buffer define BUFFER SIZE 10 define NUM OF ELEMS BUFFER SIZE 1 lt Tipos de buffer circular typedef unsigned char INT8U typedef INT8U KeyType typedef struct INT8U writePointer lt puntero de escritura INT8U readPointer lt puntero de lectura INT8U size lt tamano del buffer circular KeyType keys 0 lt elemento del buffer circular CircularBuffer lt Inicializacion del buffer circular CircularBuffer CircularBufferInit CircularBuffer pQue int size int sz size sizeof KeyType sizeof CircularBuffer pQue CircularBuffer malloc sz if pQue printf Init CircularBuffer keys d d n size sz pQue gt size size pQue gt writePointer 0 pQue gt readPointer 0 return pQue inline int CircularBufferIsFull CircularBuffer que return que gt writePointer 1 que gt size que gt readPointer inline int CircularBufferIsEmpty CircularBuffer que return que gt readPointer que gt writePointer inline int CircularBufferEnque CircularBuffer que KeyType k int isFull CircularBufferIsFull que if isFull que gt keys que gt writePointer k que gt writePointer que gt writePointer que gt size return isFull inline int CircularBufferDeque CircularBuffer que KeyType pK int isEmpty CircularBufferIsEmpty que if isEmpty pK que gt keys que gt readPointer que gt readPointer que gt readPointer que gt size return isEmpty inline int CircularBufferPrint CircularBuffer que int i 0 int isEmpty CircularBufferIsEmpty que int isFull CircularBufferIsFull que printf n Q w d r d f d e d n que gt writePointer que gt readPointer isFull isEmpty for i 0 i lt que gt size i printf d que gt keys i printf n return isEmpty int main int argc char argv CircularBuffer que KeyType a 101 int isEmpty i CircularBufferInit amp que BUFFER SIZE CircularBufferPrint que for i 1 i lt 3 i a 10 i printf n n n Test Insert d d n a a NUM OF ELEMS 1 while CircularBufferEnque que a CircularBufferPrint que printf n RX d i a 0 isEmpty CircularBufferDeque que amp a while isEmpty printf 02d a a 0 isEmpty CircularBufferDeque que amp a CircularBufferPrint que free que return 0 Un ejemplo de implementacion en C Usando todas las ranuras include lt stdio h gt include lt string h gt include lt malloc h gt Circular Buffer Example Compile gcc cbuf c o cbuf exe lt Buffer Size define BUFFER SIZE 16 lt Tipos de buffer circular typedef unsigned char INT8U typedef INT8U KeyType typedef struct INT8U writePointer lt Puntero escritura INT8U readPointer lt Puntero lectura INT8U size lt tamano del buffer circular KeyType keys 0 lt Elemento del buffer circular CircularBuffer lt Inicializacion del buffer circular CircularBuffer CircularBufferInit CircularBuffer pQue int size int sz size sizeof KeyType sizeof CircularBuffer pQue CircularBuffer malloc sz if pQue printf Init CircularBuffer keys d d n size sz pQue gt size size pQue gt writePointer 0 pQue gt readPointer 0 return pQue inline int CircularBufferIsFull CircularBuffer que return que gt writePointer 1 que gt size que gt readPointer inline int CircularBufferIsEmpty CircularBuffer que return que gt readPointer que gt writePointer inline int CircularBufferEnque CircularBuffer que KeyType k int isFull CircularBufferIsFull que que gt keys que gt writePointer k que gt writePointer que gt writePointer que gt size return isFull inline int CircularBufferDeque CircularBuffer que KeyType pK int isEmpty CircularBufferIsEmpty que pK que gt keys que gt readPointer que gt readPointer que gt readPointer que gt size return isEmpty int main int argc char argv CircularBuffer que KeyType a 0 int isEmpty CircularBufferInit amp que BUFFER SIZE while CircularBufferEnque que a do isEmpty CircularBufferDeque que amp a printf 02d a while isEmpty printf n free que return 0 Utilizar un contador de llenado del buffer Editar Esta tecnica consiste en mantener un contador de llenado que se incrementa con cada operacion de escritura y se decrementa en cada operacion de lectura esto permite conocer en todo momento el estado de uso del buffer dandonos la posibilidad de no permitir la lectura si el contador de llenado esta a cero y de no permitir la escritura si el contador de llenado esta en el valor de maxima capacidad del buffer Utilizar dos contadores uno de lecturas y otro de escrituras Editar Este metodo consiste en utilizar dos contadores uno para lectura y otro para escritura dichos contadores se iran incrementando por cada operacion correspondiente de forma que cuando realizamos una escritura aumenta el contador de escritura y similar para el contador de lectura Manteniendo este sistema podemos comprobar el estado en el que se encuentra el buffer en cualquier momento POR EJEMPLO el buffer podria estar en los siguientes estados vacio el contador de escritura y lectura coinciden saturado el contador de lectura es mayor que el de escritura o bien el contador de escritura es mayor que el de lectura mas la capacidad maxima del buffer lleno el contador de escritura es igual que el contador de lectura mas la capacidad maxima del buffer Optimizacion EditarUna implementacion del buffer circular puede ser optimizada asignando al buffer dos regiones contiguas de memoria virtual Naturalmente el tamano del buffer debe ser multiplo del tamano de pagina del sistema La lectura y escritura en el buffer circular debe realizarse con gran eficiencia en cuanto al acceso directo a memoria Ejemplo de implementacion POSIX Editar include lt sys mman h gt include lt stdlib h gt include lt unistd h gt define report exceptional condition abort struct ring buffer void address unsigned long count bytes unsigned long write offset bytes unsigned long read offset bytes Warning order should be at least 12 for Linux void ring buffer create struct ring buffer buffer unsigned long order char path dev shm ring buffer XXXXXX int file descriptor void address int status file descriptor mkstemp path if file descriptor lt 0 report exceptional condition status unlink path if status report exceptional condition buffer gt count bytes 1UL lt lt order buffer gt write offset bytes 0 buffer gt read offset bytes 0 status ftruncate file descriptor buffer gt count bytes if status report exceptional condition buffer gt address mmap NULL buffer gt count bytes lt lt 1 PROT NONE MAP ANONYMOUS MAP PRIVATE 1 0 if buffer gt address MAP FAILED report exceptional condition address mmap buffer gt address buffer gt count bytes PROT READ PROT WRITE MAP FIXED MAP SHARED file descriptor 0 if address buffer gt address report exceptional condition address mmap buffer gt address buffer gt count bytes buffer gt count bytes PROT READ PROT WRITE MAP FIXED MAP SHARED file descriptor 0 if address buffer gt address buffer gt count bytes report exceptional condition status close file descriptor if status report exceptional condition void ring buffer free struct ring buffer buffer int status status munmap buffer gt address buffer gt count bytes lt lt 1 if status report exceptional condition void ring buffer write address struct ring buffer buffer void pointer arithmetic is a constraint violation return buffer gt address buffer gt write offset bytes void ring buffer write advance struct ring buffer buffer unsigned long count bytes buffer gt write offset bytes count bytes void ring buffer read address struct ring buffer buffer return buffer gt address buffer gt read offset bytes void ring buffer read advance struct ring buffer buffer unsigned long count bytes buffer gt read offset bytes count bytes if buffer gt read offset bytes gt buffer gt count bytes buffer gt read offset bytes buffer gt count bytes buffer gt write offset bytes buffer gt count bytes unsigned long ring buffer count bytes struct ring buffer buffer return buffer gt write offset bytes buffer gt read offset bytes unsigned long ring buffer count free bytes struct ring buffer buffer return buffer gt count bytes ring buffer count bytes buffer void ring buffer clear struct ring buffer buffer buffer gt write offset bytes 0 buffer gt read offset bytes 0 template class Queue template lt class T gt class Queue T qbuf buffer data int qsize int head index begin data int tail index stop data inline void Free if qbuf 0 delete qbuf qbuf 0 qsize 1 head tail 0 public Queue qsize 32 qbuf new T qsize head tail 0 Queue const int size qsize 1 qbuf 0 head 0 tail 0 if size lt 0 size amp size 1 throw Value is not degree of two qsize size qbuf new T qsize head tail 0 Queue Free void Enqueue const T amp p if IsFull throw Queue is full qbuf tail p tail tail 1 amp qsize 1 Retrieve the item from the queue void Dequeue T amp p if IsEmpty throw Queue is empty p qbuf head head head 1 amp qsize 1 Get i element with not delete void Peek const int i T amp p const int j 0 int k head while k tail if j i break j k k 1 amp qsize 1 if k tail throw Out of range p qbuf k Size must by 1 2 4 8 16 32 64 void Resize const int size if size lt 0 size amp size 1 throw Value is not degree of two Free qsize size qbuf new T qsize head tail 0 inline void Clear void head tail 0 inline int GetCapacity void const return qsize 1 Count elements inline int GetBusy void const return head gt tail qsize 0 tail head true if queue if empty inline bool IsEmpty void const return head tail true if queue if full inline bool IsFull void const return tail 1 amp qsize 1 head Use Queue lt int gt Q Q Enqueue 5 Q Enqueue 100 Q Enqueue 13 int len Q GetBusy int val Q Dequeue val Datos Q1224994 Multimedia Category Circular buffersObtenido de https es wikipedia org w index php title Buffer circular amp oldid 130662784, wikipedia, wiki, leyendo, leer, libro, biblioteca,

español

, española, descargar, gratis, descargar gratis, mp3, video, mp4, 3gp, jpg, jpeg, gif, png, imagen, música, canción, película, libro, juego, juegos