2부에서 싱글톤 문제가 그렇게 해결 되는 듯 했다.
그런데 봇 테스트 중 가끔 일부 쓰레드가 정지되는 경우가 발생했다.
디버깅을 해보니 'DeadLock'이었다.
그리고 그 'DeadLock'의 원인은 바로 2부에서 작성했던 Singleton Locker때문이었다.
싱글톤 사용 시 Lock을 걸다보니 A싱글톤 내부에서 B싱글톤을 호출하고, B싱글톤 내부에서 A싱글톤을 호출하는 경우에 DeadLock이 발생했다.
언제나 그렇듯 이 사실은 안 순간 정말 절망이었다..
그렇다면 모든 싱글톤 소스에서 타 싱글톤 호출하는 부분을 찾아서 수정해야 된단 말인가....ㅡㅡ;
처음 싱글톤 문제를 알았을 때 처럼...백지화할까라는 생각이 들었다.
그래도 어떻게든 해법을 찾고 싶었다. 그래서 제작하게 된 것인 DeaLock Checker이다.
'DeadLock'...
아마 멀티 쓰레드 프로그래밍을 사용하다보면 필연적으로 마주치게 되는 버그 중 하나다.
골치 아픈 버그들이 그렇듯 DeadLock이 발생하면 당황할 수 밖에 없는 이유는 '재현이 잘 안되는 버그'이기 때문이다.
정말 작은 한 순간 타이밍의 틈을 비집고 들어와서 시원하게 꽝~~하고 터져 버린다.
DeadLock의 특징은 항상 터질 '가능성'을 가지고 있다가 아주 작은 타이밍적인 우연의 일치가 맞았을 때 터진다는 점이다.
내가 주목했던 점은 바로 그 '가능성'이다.
만약 아직 터지지는 않았지만 현재 코드가 가능성을 가지고 있다면, 그 '가능성'이라는 측면을 미리 확인 할 수 있는 방법이있을 꺼라고 생각했다.
예를 들어 '가'쓰레드와 '나'스레드가 있다.
그 중 '가' 쓰레드가 'A' CS를 호출하고, '나'쓰레드가 'B' CS를 호출한다.
아주 가끔 '가'쓰레드가 'A' CS를 호출 후 'B' CS를 호출하는 경우고 있고, '나'쓰레드의 경우 그 반대의 경우가 가~끔 있다.
아마 몇 번의 테스트에서는 괜찮겠지만, 아주 가끔 DeadLock이 발생할 여지가 있다.
그렇다면 각 쓰레드별 CS 호출 기록을 남기면 어떨까?
예를 들어 라이브 서비스 하기 전에 로봇 테스트나 사내 테스트를 진행 할 때 세팅을 하면 각 쓰레드별 CS호출 기록을 남기는 것이다.
그리고 서버 종료 시점이나 매우 긴 틱에 각각의 쓰레드간에 서로 크로스 하는 경우가 없는 지 검사하는 것이다.
다소 무식하고, 성능은 떨어지겠지만 DeadLock의 가능성을 미리 알 수 있다.
이 아이디어를 처음 생각했을 때 좀 무식하기는 하지만, 라이브 서비스에서는 해당 기능을 꺼버리면 되니
성능 문제는 없으므로 알고리즘만 잘 짜여지면 나름 괜찮은 방법이라고 생각했다.
하지만 한편으로는 과연 이렇게까지 해야지만 DeadLock이 검출될 정도로 복잡도가 높고, 쓰레드간 모듈화가 제대로
되지 않았다면, 그 것 자체가 문제이지는 않을까 라는 생각도 들었다....
다행이 지금 프로젝트는 그 정도까지는 아니었지만, 나중에 이거 믿고 너무 멀티 쓰레드를 남발하는 경우는 조심해야 될 것 같다.
그리고 아직 문제가 남았으니....
그렇다면 각 쓰레드별 CS호출 기록을 어떻게 모두 남길 것이며..어떻게 검사 할 것인가~라는 문제가 남았다.
이 부분은 회사 소스코드를 사용할 수 없으니 테스트 프로젝트로 남겨야 될 것 같다.
'하루하루 > 개발' 카테고리의 다른 글
Multi-Logic-Threaded GameServer 2부 (0) | 2010.04.12 |
---|---|
Multi-Logic-Threaded GameServer 1부 (0) | 2010.04.09 |
LFH (Low Fragmentation Heap) (0) | 2009.04.12 |
Mock 객체 활용법 (1) | 2008.04.29 |