링 버퍼란? 

고정된 크기의 큐의 양 끝을 이어 원형 모양처럼 사용하는 버퍼

데이터를 넣었다가 빼는 역할을 할 수 있다 

 

구현은 다음과 같이 하였다.

 

ring_buffer.h

#include <stdint.h>
#include <string.h>

typedef struct{
	uint8_t *buffer;
	int front;
	int rear;
	int maxlen;
}ring_buffer_t;

void ring_buf_init(ring_buffer_t *rbuf, uint8_t *buffer, int size);
uint8_t ring_buf_push(ring_buffer_t *rbuf, uint8_t data);
uint8_t ring_buf_pop(ring_buffer_t *rubf, uint8_t *data);
uint8_t ring_buf_is_full(ring_buffer_t *rbuf);
uint8_t ring_buf_is_empty(ring_buffer_t *rbuf);
void ring_buf_clear(ring_buffer_t *rbuf);

ring_buffer_t는

사용할 버퍼를 담을 uint_t *buffer 와 큐를 사용하기 위한 fornt, rear와 사용할 버퍼의 크기를 maxlen으로 한다.  

 

ring_buffer.c

#include <stdint.h>
#include <string.h>

void ring_buf_init(ring_buffer_t *rbuf, uint8_t *buffer, int size){
	memset(rbuf, 0x00, sizeof(ring_buffer_t));
	rbuf->buffer=buffer;
	rbuf->maxlen=size;
}

uint8_t ring_buf_is_full(ring_buffer_t *rbuf){
	if(rbuf->rear == ( rbuf->front+1 ) % rbuf->maxlen) return 1;
	else return 0;
}
uint8_t ring_buf_is_empty(ring_buffer_t *rbuf){
	if( rbuf->rear == rbuf->front) return 1;
	else return 0;
}

uint8_t ring_buf_push(ring_buffer_t *rbuf, uint8_t data){
	if( ring_buf_is_full(rbuf) ) return 0;
	rbuf->buffer[rbuf->front] = data;
	rbuf->front = ( rbuf->front + 1) % rbuf->maxlen;
	return 1;

}
uint8_t ring_buf_pop(ring_buffer_t *rbuf, uint8_t *data){
	if( ring_buf_is_empty(rbuf) ) return 0;
	*data=rbuf->buffer[rbuf->rear];
	rbuf->rear = (rbuf->rear + 1) % rbuf->maxlen;
	return 1;
}

void ring_buf_clear(ring_buffer_t *rbuf){
	rbuf->front=0;
	rbuf->rear=0;
}

 

사용 예시

#include <stdio.h>
#include <stdint.h>
#include "ring_buffer.h"

int main(){
    uint8_t  i=0;
    uint8_t pop_data=0;
    ring_buffer_t ring_buffer;
    uint8_t rbuf[3];

    ring_buf_init(&ring_buffer, rbuf, 3);

    for(i=0;i<5;i++){
        if (ring_buf_push(&ring_buffer, i)){
             printf("push data : %d\r\n",i );
        }
    }

    for(i=0;i<5;i++){
        if (ring_buf_pop(&ring_buffer,&pop_data)){
            printf("pop %d \r\n", pop_data);
        }
    }
    return 0;
}

1. ring_buf_init(&ring_buffer, rbuf, 3);

    -> ring_buffer 구조체에 rbuf로 초기화 한다. 

2. 0~5를 ring buffer에 순차적으로 push 한다.

3.  ring_buffer의 데이터를 pop_data에 5번 pop한다. 

 

결과 

 

rbuf의 크기는 3인데 데이터는 2개를 넣은 후, 3개째에서 링 버퍼가 가득 찼다고 나온다. 

이는 링 버퍼의 경우,  empty와 full을 구분하기 위해 full의 경우 한 칸을 비워두기 때문이다.

 

나는 3개를 만들었으면 3개를 다 쓰고 싶다고 한다면 ring_buffer.h에서 ring_buffer_init 할 때 maxlen을 버퍼의 크기보다 1개 더 크게 해주면 된다. 

void ring_buf_init(ring_buffer_t* rbuf, uint8_t* buffer, uint16_t size){
    memset(rbuf,0x00,sizeof(ring_buffer_t));
    rbuf->buffer = buffer;
    rbuf->maxlen = size+1;
}

이렇게 고치고 똑같이 테스트를 하면

버퍼의 크기만큼 모두 이용할 수 있다. 

물론 테스트를 많이 안해봐서 오류가 있을 수도.....

 

반응형

+ Recent posts