본문 바로가기

하루하루/개발

Multi-Logic-Threaded GameServer 2부

문제는 '싱글톤'이었다.

기존에는 Logic Thread가 하나 였고, 대부분의 싱글톤은 게임과 관련된 싱글톤이었기 때문에,

문제가 되지 않았다.

그러나 이제 다수 Logic Thread가 돌아가면서, 여기 저기에서 싱글톤에 접근하다보니..

문제가 여기 저기서 발생했다.

그리고 막상 Lock을 걸려고 하니 문제가 될만하는 요소가 너무 커보였다.

1. 코드 상에서 싱글톤에 접근하는 곳이 수십~수백곳에 달하다 보니 일일이 Lock을 걸수도 없고, 관리도 힘들것 같았다.

2. 싱글톤에서 사용 중인 모든 함수 시작부터 끝까지 Lock을 걸기에도 힘들고, 관리도 힘들것 같았다.

3. 더욱이 싱글톤에서 포인트를 가져와서 Logic Thread에서 데이터를 변형하는 경우 위에 1. 2. 다 하더라도 위험할 소지가 있었다.


좀..절망적이었다. 아직 코드 작업은 안 했으니깐, 백지화할까...라는 생각도 들었다.

그런데 옆에 앉은 부사수는 계속 삽질하고 있고,

혹시나 DB Object를 Logic Thread에서 사용할 수 있다면, 편해질꺼라도 믿고 있으니....

자칫 섣불리 뛰어들었다가 오히려 복잡도가 상승하여 배보다 배꼽이 더 커지는 모양이 될 것 같았다.

일단 어떤 방법을 사용하든 클라이언트와 공용으로 사용하는 코드가 있어서 기존 코드에 너무 많은 수정을 하는 방법은

피해야 되었다.

그 때 평소에 싱글톤 선언 때 사용하는 매크로가 눈에 보였다.


#define JDefSingleton(ClassName) \
     inline ClassName* _##ClassName##() { return ClassName::GetInstance(); }


위와 같이 선언함으로써 싱글톤을 사용할 때 아래와 같이 사용한다.


int nOK = _JGuildManager()->LevelUp( m_nGuildUID );


음...CriticalSection을 쉽고 안전하게 사용하기 위해 사용하는 Locker와 비슷하면서 싱글톤을 호출하는

딱 위에 1줄에만 Lock을 걸수 있는 방법을 고민해보았다.

그래서 아래와 같이 수정하였다.


 #define JDefSingleton(ClassName) \
 inline JSingletonLocker<ClassName> _##ClassName##() \
 { \
     static JCriticalSection jClassCS; \
     return JSingletonLocker<ClassName>( &jClassCS, ClassName::GetInstance() ); \
 }


JSingletonLocker는 생성자에서 Lock을 걸고, 소멸자에서 UnLock을 한다.
( 기본은 Locker와 동일 )

그리고 아래와 같은 operator을 정의한다.

 operator T*() { return m_pParent; }
 T* operator*() { return m_pParent; }
 T* operator->() { return m_pParent; }
 T* get() { return m_pParent; }

쉽게 생각하면 SmartPointer와 비슷하다고 생각하면 된다.

복사생성자만 유의해서 만들면 쉽게 만들 수 있다.
( 짧은 코드지만 풀 소스는 회사코드라..;; )

그리고 JCriticalSection은 CRITICAL_SECTION을 가지고 있으며, Lock(), UnLock() 함수만 가지고 있는 심플한 클래스이다.

이렇게 테스트 코드를 작성해서 돌려보았을 때 큰 문제를 발견하지 못 했다.

이 방법의 최고 장점은 서버에서 사용하는 매크로를 수정하면, 기존 소스코드에는 전~혀 손을 대지 않아도 되었다.

그래서 처음 테스트 코드를 만들었을 때 'Alleh~'를 외쳤다..

그런데.. 가만히 생각해보니 안타깝게도 3번 문제가 해결되지 않는다.ㅜ.ㅜ

대부분의 경우 싱글톤에서 가져온 데이터를 외부에서 변경하는 경우는 없을 것 같아서,

그 당시 싱글톤 사용 중인 모든 곳을 확인했다. ( 정말 무식한 방법...;;; )

그리고 수백 곳 중에 그렇게 사용하는 곳이 한군데도 없다는 것을 확인했다.
( 대부분 복사하거나 const 사용 중이었음 )

대부분 싱글톤 객체가 소유한 데이터에 대한 변경은 싱글톤 함수를 통해서 이루졌으며

싱글톤 객체가 소유하고 있는 데이터를 외부에서 다른 객체가 직접 변경하는 일은

의미적으로 이상하다보니 안 쓰였다.

그래서 이때까지 그랬듯 앞으로도 외부에서 데이터를 변경하지는 않게 내부 규약을 정했다.
( 자동으로 확인할 수 있는 방법이 있었으면 좋겠다...ㅜ.ㅜ )

그렇게 싱글톤에 대한 문제는 일단락 되는 듯 했다.

그래서 위와 같이 프로그래밍을 완료해서 봇 테스트를 하였다.

그리고 멀티 쓰레드 프로그래밍의 숙명인 'Deadlock'과 마주치게 되었다.
 

'하루하루 > 개발' 카테고리의 다른 글

Multi-Logic-Threaded GameServer 3부  (0) 2010.05.17
Multi-Logic-Threaded GameServer 1부  (0) 2010.04.09
LFH (Low Fragmentation Heap)  (0) 2009.04.12
Mock 객체 활용법  (1) 2008.04.29