2009년 05월 03일
멀티 코어와 메시징
멀티 코어는 여러 개의 쓰레드를 사용하게 된다. 이런 환경에서 가장 문제가 되는 것은 공유 데이터에 대한 접근 방법이다. 물리 시스템이 하나의 쓰레드를 사용하고 렌더링 시스템 역시 쓰레드를 사용하여 분리한 경우를 보자.
게임 루프에서 충돌이 일어난 후 물리 시스템은 충돌 이벤트에 대해서 게임 객체의 새로운 위치를 계산한다. 그리고 렌더링 시스템에서는 갱신된 새로운 위치 데이터를 사용하여 게임 객체를 렌더링한다. 그런데 이들 두 시스템이 각각의 쓰레드로 분리되어 실행되고 있다는 점이다.
일반적인 방법으로는 lock을 사용한다. 물리 시스템에서 게임 객체의 위치를 갱신하기 전에 다른 시스템에서 이 데이터에 접근하지 못하도록 lock을 건 다음 데이터를 갱신한다.
그런데 이 lock의 오버헤더가 만만치 않다. 또 이런 식으로 lock/unlock을 사용하면 전체 시스템이 복잡해지는 것은 두말할 필요도 없다. 행여 실수로 lock/unlock을 빠뜨리는 경우 시스템은 예기치 않은 오동작을 하게 된다. 더 큰 문제는이 문제가 바로 쓰레드와 관련한 문제라는 것이다. 복잡한 시스템에서 쓰레드의 문제는 해결하기가 매우 어려운 경우가 대부분인데다 심지어는 재앙을 초래하기도 한다.
그럼, 쓰레드를 사용해서 동시에 여러 개의 시스템을 실행할 때 이들 시스템 간의 데이터 공유 문제에 해결에는 어떤 방법이 좋을까?
바로 데이터를 복사하는 방법이다. 이것은 시스템이 서로 다른 시스템의 데이터에 접근하는 방법이 아니라 각 시스템이 시스템 내부에 공유 데이터의 복사본을 가지고 있고 메시지를 통해서 다른 시스템에 자기 시스템에서의 공유 데이터의 변경을 알리는 방법이다.
쓰레드 A에서 쓰레드 B의 함수를 바로 호출하는 방법도 사실은 다른 시스템의 데이터에 lock을 통해서 바로 접근하는 방법에 속한다. 메시지를 통해서 공유 데이터를 복사하는 방법은 이러한 lock을 사용할 필요가 없거나 혹은 최소한의 lock이 필요할 따름이다. 메시지는 특별한 형태가 아니라 일반적으로 알고 있는 바와 같이 다음과 유사한 형태로 처리할 수 있다.
일전[1]에 망갈로 게임 프레임워크의 메시지 시스템의 장점 중에 하나로 멀티 코어 시스템에 편리하다고 이야기한적이 있었는데 바로 이런 이유에서다. 또 이렇게 메시지를 사용하게 되면 각 시스템을 서로 완전히 분리(decoupling) 시킬 수가 있는데 이것 역시 멀티 코어를 사용하여 각 시스템들을 동시에 실행시킬 때에는 매우 중요한 것 중의 하나이다.
컴포넌트 방식의 게임 프레임워크[2]에서 컴포넌트 간의 통신에 메시지를 사용하게 되면 이처럼 멀티 코어 환경에서도 잘 작동하는 유용하고 견고한 시스템의 설계가 가능하다.
[1] KGC 2008, Nebula2 Mangalore Game Framework에서
[2] GPG6, Component based Game Framework Library
...이렇게 메시지를 사용하게 되면 이제 메시지 전달의 순서에 대한 문제가 대두됩니다. 무슨 말이냐 하면 물리 시스템의 위치 메시지는 렌더링 시스템의 위치 메시지보다 먼저 처리되어야 합니다. 바꾸어 말하면 물리 시스템에서 계산된 위치 데이터를 계산한 다음 이 메시지가 렌더링 시스템에 전달되어야 순서에 맞습니다다. 이 부분은 또 다음에... ^^
게임 루프에서 충돌이 일어난 후 물리 시스템은 충돌 이벤트에 대해서 게임 객체의 새로운 위치를 계산한다. 그리고 렌더링 시스템에서는 갱신된 새로운 위치 데이터를 사용하여 게임 객체를 렌더링한다. 그런데 이들 두 시스템이 각각의 쓰레드로 분리되어 실행되고 있다는 점이다.
일반적인 방법으로는 lock을 사용한다. 물리 시스템에서 게임 객체의 위치를 갱신하기 전에 다른 시스템에서 이 데이터에 접근하지 못하도록 lock을 건 다음 데이터를 갱신한다.
그런데 이 lock의 오버헤더가 만만치 않다. 또 이런 식으로 lock/unlock을 사용하면 전체 시스템이 복잡해지는 것은 두말할 필요도 없다. 행여 실수로 lock/unlock을 빠뜨리는 경우 시스템은 예기치 않은 오동작을 하게 된다. 더 큰 문제는이 문제가 바로 쓰레드와 관련한 문제라는 것이다. 복잡한 시스템에서 쓰레드의 문제는 해결하기가 매우 어려운 경우가 대부분인데다 심지어는 재앙을 초래하기도 한다.
그럼, 쓰레드를 사용해서 동시에 여러 개의 시스템을 실행할 때 이들 시스템 간의 데이터 공유 문제에 해결에는 어떤 방법이 좋을까?
바로 데이터를 복사하는 방법이다. 이것은 시스템이 서로 다른 시스템의 데이터에 접근하는 방법이 아니라 각 시스템이 시스템 내부에 공유 데이터의 복사본을 가지고 있고 메시지를 통해서 다른 시스템에 자기 시스템에서의 공유 데이터의 변경을 알리는 방법이다.
쓰레드 A에서 쓰레드 B의 함수를 바로 호출하는 방법도 사실은 다른 시스템의 데이터에 lock을 통해서 바로 접근하는 방법에 속한다. 메시지를 통해서 공유 데이터를 복사하는 방법은 이러한 lock을 사용할 필요가 없거나 혹은 최소한의 lock이 필요할 따름이다. 메시지는 특별한 형태가 아니라 일반적으로 알고 있는 바와 같이 다음과 유사한 형태로 처리할 수 있다.
... //메시지 생성 Message::MoveMsg moveMsg = Message::MoveMsg::Create(); //메시지 값의 설정 moveMsg.Set(x, y, z); // 메시지의 전송 moveMsg.SendAsync(); ... |
일전[1]에 망갈로 게임 프레임워크의 메시지 시스템의 장점 중에 하나로 멀티 코어 시스템에 편리하다고 이야기한적이 있었는데 바로 이런 이유에서다. 또 이렇게 메시지를 사용하게 되면 각 시스템을 서로 완전히 분리(decoupling) 시킬 수가 있는데 이것 역시 멀티 코어를 사용하여 각 시스템들을 동시에 실행시킬 때에는 매우 중요한 것 중의 하나이다.
컴포넌트 방식의 게임 프레임워크[2]에서 컴포넌트 간의 통신에 메시지를 사용하게 되면 이처럼 멀티 코어 환경에서도 잘 작동하는 유용하고 견고한 시스템의 설계가 가능하다.
[1] KGC 2008, Nebula2 Mangalore Game Framework에서
[2] GPG6, Component based Game Framework Library
...이렇게 메시지를 사용하게 되면 이제 메시지 전달의 순서에 대한 문제가 대두됩니다. 무슨 말이냐 하면 물리 시스템의 위치 메시지는 렌더링 시스템의 위치 메시지보다 먼저 처리되어야 합니다. 바꾸어 말하면 물리 시스템에서 계산된 위치 데이터를 계산한 다음 이 메시지가 렌더링 시스템에 전달되어야 순서에 맞습니다다. 이 부분은 또 다음에... ^^
# by | 2009/05/03 18:17 | MultiCore | 트랙백 | 덧글(7)
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
시스템 전체가 저런 방식으로 일관성 있게 디자인 되어있더군요. 많은 것은 배우고 있습니다.
(메인 개발자분인 floh 님도 참 대단한 듯...)
lock-ordering때문에 머리아프던 문제가 메시징을 쓰면 깔끔하게 풀리는 경우가 참 많더라고요~_~
framebatch 쪽이랑 visResolver 쪽을 봐도 관련된 SortingMode 열거체는 있는데 딱히 적용하는 코드가 안보이네요.. 제가 못 찾는건지 ^^;; ㅎㅎ