Edward입니다.
상기 제목처럼
1. Ringbuffer란?
2. Ringbuffer를 사용하는 이유
에 대해 설명해보겠습니다.
먼저,Ringbuffer란 다들 아시다시피 원형 큐인데요.
이 원형 큐라는 것을 이해하시려면 먼저 선형 큐(queue) 라는 것을 아셔야합니다.
이 선형 큐(Queue)라는 것은 FIFO(First in First out)의 능력을 가진 녀석이에요.
FIFO는 선입선출이라는 능력을 가진 녀석으로 첫번째에 들어간 Data가 가장 처음으로 출력되는 녀석이죠.
이 Data들이 54321 -> | Databus | -> 54321 이렇게 처음에 들어간 Data가 가장 처음에 출력하는 능력을 가진 녀석입니다.
이 FIFO의 능력을 기반으로 만든 것이 선형 큐(queue)이구요. Software 측으로 보시면 하나의 메모리(버퍼) 영역입니다.
그리고 원형 큐(Ringbuffer)는 이 선형큐에서 n+1시킨 것입니다.
n+1이 무엇이냐면, 선형 큐는 n개의 메모리를 가지고 있잖아요? (n개의 메모리는 사용자가 지정해주기에 따라 다르죠)
그런데 선형 큐의 메모리가 꽉 차게되면 Overflow가 된다. 즉 더이상 data를 쓸 수 없다. 그래서 나온게 n+1 = 0 입니다.
n개의 메모리가 증가하다가 n+1이 되면 0으로 다시 돌아간다. 라는 의미입니다.
위의 그림과 같이 Data를 쭉~ Write하다가 꽉차면 n+1되서 0으로 돌아가서 이어서 Data를 써준다는 의미입니다.
링버퍼는 이러한 놈이구요.
이 FIFO에 반대되는 개념이 있어요 일명 STACK이라고 불리는 LIFO(Last in First out)이 있어요.
얘는 말그대로 맨 마지막에 입력된 Data가 가장 처음에 출력되는 녀석이에요.
54321 -> | Databus | -> 12345 이렇게요 ㅎㅎ
2. Ringbuffer를 사용하는 이유!
아마도 이게 더 궁금하시지 않나 하는 생각이 듭니다.
우리가 구현해야할 프로그램은 채팅 프로그램입니다. 초기강좌부터 쭉 봐오셨던 분들이면 잘 아시겠지만, 우리는 채팅 프로그램을 서버 - 클라이언트로 나뉘어서 TCP/IP 통신으로 시도할거에요.
그런데, 저번시간에 언급하였다시피, UART Data를 버퍼에 넣고 그걸 그대로 전송해버리면 Data출력이 덜 출력됩니다.
이유는 (내가 Server일 때) Main문에서 Client로 부터 Data를 받으면 그냥 Serial로 출력해서 보여줍니다. 이건 어렵지 않죠?
그런데, UART data를 읽어서 보낼때는 인터럽트를 사용하잖아요? (이게 문제..)
Main문에서 폴링으로 UART data 읽어서 보내는 도중에 또 interrupt가 걸려버리면 보내던 Data는 손실되서 없어지게 되고,(일명 짤린다..)
또 interrupt로 UART data 읽어서 Ethernet으로 Data 보내주는 도중에 또 interrupt가 걸리면 Data가 덜 출력되게 되죠.
이래서 Ringbuffer를 사용합니다.
Ringbuffer를 사용하기 가장 좋은 장점은 포인터를 2개를 사용한다는 것이에요.
(이해하기 쉽게) Write 포인터, Read 포인터 두개를 내가 선언했다고 합시다.
그러면 내가 Write 포인터를 써서 UART를 받을 수신버퍼에 Data를 Write합니다. (예를들어 5개(5byte)가 왔다고 합시다.)
그리고 5Byte의 Data를 read 포인터로 읽어서 Ethernet에 출력해주는 거죠.
그러면 어떻게되냐.. interrupt되서 받은 UART Data가 Ethernet으로 출력되고 있을때, 다시 interrupt가 걸리면!!
Write 포인터에 의해 수신버퍼에 Data만 기록하게되고, UARTdata를 다 보낸 다음에!! 다시 Read 포인터로 읽어서 보내면 된다. 이거죠.
만약, 제가 써논 말이 이해가 안되시면
밑의 블로그를 참조해보세요.
참조 - http://charang.tistory.com/13
블로그를 참조하셔서 링버퍼가 어떤건지 아신 다음에 제 글을 다시 한번 읽어보시면 이해되시리라 생각이 듭니다.
더 이해가 안되신다면 코드를 블로깅할테니 코드를 보시면 되겠습니다.