SpinBuffer
알고리즘
-
버퍼는 0, 1, 및 2로 주문된다. 0의 다음 버퍼는 1이다, 그 후에 1의 다음 버퍼는 2이고, 마지막으로, 2의 다음 버퍼는 0이다. 두개의 포인터가 운용된다 — 하나는 Reader가 읽을 위치를 가르키고 다른 하나는 Writer 쓸 곳을 가르킨다. 언제든지 읽을 버퍼(R)가 할당 될 수 있고 쓸 버퍼(W)가 할당 될수 있으며 해제 버퍼(F)가 있다. 버퍼는 고정크기의 배열로 구현 될 수 있다.
-
put 메소드는 다음과 같다.
- 쓰기 버퍼에 아이템을 넣는다.
- 만약 다음버퍼가 해제(2)된 버퍼면, 해제(2)된 버퍼를 쓰기 버퍼(2->0)로 만들고 현재의 쓰기 버퍼(0->1)를 해제한다.
-
get 메소드는 다음과 같다.
- 읽기 버퍼에서 아이템을 꺼낸다.
- 만약 현재 읽기 버퍼(1)가 비어있고 다음 버퍼(0)가 해제된 것이라면 다음 버퍼(0)를 읽기 버퍼(0->1)로 만들고 현재 버퍼(1->2)를 해제한다.
특징
- 다음 버퍼가 사용중인지 체크하는 부분(busy)만 Lock를 걸면 되는데 이 부분은 Interlocked.. 계열 함수로 Atomic Operation을 보장 하는게 가능하므로 Lock Free 한 구현이 가능.
- Producer와 Consumer가 각 한 명씩일때만(접근하는 스레드가 하나씩) 사용 가능한 모델
적용예시
- Client에서 사용하는 NetworkInterface에 사용했음. Recv스레드에서 받은 패킷을 쌓아주고(Producer) 게임 로직 루프에서 받은 패킷을 꺼내어 처리(Consumer)
- 아래 주의 사항의 첫번째 이유로 NetworkInterface에서 제거하고 MwmrQueue(내부적으로 Lock을 처리하는 Queue)로 교체했음. put(null)을 Producer 스레드에서 지속적으로 불러주어야 하는데 구조상 Producer스레드는 이벤트가 발생해야 불리므로 적합한 사용예가 아닌것 같음
- Producer 스레드와 Consumer 스레드가 하나씩이고 둘 다 지속적으로 불리는 상황이어야 사용할 수 있을것 같음
주의 사항
- SpinBuffer의 Reader 그리고 Writer는 매번 호출되어야 한 다. 그렇지 않으면, 버퍼의 아이템이 Reader에 의해 회수되지 않는 상황이 전개된다. 이것은 Writer가 쓸게 없을때 일어난다. put이 호출되지 않으면 쓰기 버퍼의 아이템은 Reader에 의해 절대 읽혀지지 않는다. 쓰기 버퍼를 다음 버퍼로 강제로 넘기는 방법으로 null로 put을 호출하여( put(null) ) Reader 쓰레드가 버퍼의 아이템에 접근 할 수 있다.
- SpinBuffer는 천천히 읽어서 쓰기가 느려지거나 그 반대의 경우와 같은 맞지 않은 상황에 신경 써야 한다. 비슷한 빈도로 읽기와 쓰기가 호출되어야 최고의 성능이 나온다.
출처
- 영어원문 : http://www.ddj.com/architect/199902669?pgno=2
- 카페번역 : http://cafe.naver.com/ongameserver/1003
-
참고할 만한 글
편집 및 작성자
- 작성자 : 온라인 서버 개발자 카페 [야차아]
- 편집자 :
임영기 ( javawork93@gmail.com )
Comments (0)