2. CGCIICho sanghyun’s Game Classes II
SEH 란 ?
SEH(Structured Exception Handling) 은 윈도즈 O/S 차원의 예외 처리 시스템이다 .
SEH 는 C++ Exception 과 별개이며 언어 중립적이다 .
(C++ 의 try, catch 에는 잡히지 않는다 .)
일반적으로 ‘뻑 !’ 났을 때 덤프 남기는 용도로 많이 사용한다 !!
보통 SEH 의 사용은 여기까지다 .
덤프 남기는 것만으로도 감사 감사 ~
Structured Exception Handling
예외처리
(Divide by zero, Access Violation at …! 등등 )
try
throw
catch
__try
__ exception
__finally
C++ Exception SEH
3. CGCIICho sanghyun’s Game Classes II
SHE 란 ?예외처리
하지만 C++ Exception 보장 처리와 SEH 를 연동 처리
하면 뻑이 나도 다운되지 않고 안전하게 동작 가능한 서버를
만들 수 있다 .
그렇다면 !
SEH 로 Windows System Exception 만
무모화 시킨다면 다운 없는 서버 !!!?
오히려 더 큰일난다 !
→ 예외 중립 훼손
( 즉 뻑 ! 났는지도 모르고 아무런 처리도 없이 그냥 넘기면 더 큰일남 )
4. CGCIICho sanghyun’s Game Classes II
SEH 와 C++ Exception 의 결합
Visual C++ 의 Project 의 Property 에서 /EHa 옵션을 설정한다 .
즉 C++ Exception 과 SEH 가 연동될 수 있도록 옵션을 설정한다 .
예외처리
5. CGCIICho sanghyun’s Game Classes II
SEH 사용 (1)
보통 뻑이 나면 Mini-Dump 를 남기는 용도로만 사용한다 .
void fSEHTranslator(unsigned int, LPEXCEPTION_POINTERS p_pException)
{
…
CreateDump(p_pException);
…
printf(“ 뻑났슈 !!! 코딩 이렇게 밖에 못해 ?!!”);
}
void main()
{
// 쓰레드마다 설정해 주어야 한다 .
_set_se_translator(&fSEHTranslator);
…
// 뻑 유발자 코드 ( 처리 중 뻑나면 fSEHTranslator 함수를 실행할 것이다 !)
*(int*)0 = 10;
}
void fSEHTranslator(unsigned int, LPEXCEPTION_POINTERS p_pException)
{
…
CreateDump(p_pException);
…
printf(“ 뻑났슈 !!! 코딩 이렇게 밖에 못해 ?!!”);
}
void main()
{
// 쓰레드마다 설정해 주어야 한다 .
_set_se_translator(&fSEHTranslator);
…
// 뻑 유발자 코드 ( 처리 중 뻑나면 fSEHTranslator 함수를 실행할 것이다 !)
*(int*)0 = 10;
}
예외처리
6. CGCIICho sanghyun’s Game Classes II
SEH 와 C++ 예외의 결합
void fSEHTranslator(unsigned int, LPEXCEPTION_POINTERS p_pException)
{
CreateDump(p_pException);
throw std::exception();
}
void main()
{
// 쓰레드마다 설정해 주어야 한다 .
_set_se_translator(&fSEHTranslator);
…
try
{
// 뻑 유발자 !! ( 처리 중 뻑나면 std::exception() 이 발생할 것이다 !!)
*(int*)0 = 10;
}
catch(…)
{
printf(“ 뻑났음 !”);
}
}
void fSEHTranslator(unsigned int, LPEXCEPTION_POINTERS p_pException)
{
CreateDump(p_pException);
throw std::exception();
}
void main()
{
// 쓰레드마다 설정해 주어야 한다 .
_set_se_translator(&fSEHTranslator);
…
try
{
// 뻑 유발자 !! ( 처리 중 뻑나면 std::exception() 이 발생할 것이다 !!)
*(int*)0 = 10;
}
catch(…)
{
printf(“ 뻑났음 !”);
}
}
2. C++ Exception 을 던진다 !!!!
3. 그럼 C++ Exception 이 여기서 튀어나온다 !!
4. 당연히 C++ Exception 은 여기에서 잡힌다 !
1. 여기서 ‘뻑’난다 !!!
( 이 순간 C++ Exception 이 발생하지 않고 SEH 에 의해 ...)
예외처리
C++ Exception 과 함께 사용하면 좀더 다른 처리가 가능하다 .
7. CGCIICho sanghyun’s Game Classes II
CGCII 예외 시스템
void CExecutorIOCP::Execute(DWORD p_tickWait)
{
// 쓰레드마다 설정해 주어야 한다 .
_set_se_translator(&fSEHTranslator);
while(m_bDone)
{
DWORD dwResult;
DWORD dwBytes;
ULONG_PTR pHKey;
LPOVERLAPPED pOverlapped;
dwResult = GetQueuedCompletionStatus(m_hCP, &dwBytes, &pHKey, &pOverlapped, p_tickWait);
ICGExecutable* pExecuable = static_cast<ICGExecutable*>(pOverlapped);
pExecutable->ProcessExecute(dwResult, dwBytes);
pExecutable->Release();
}
}
void CExecutorIOCP::Execute(DWORD p_tickWait)
{
// 쓰레드마다 설정해 주어야 한다 .
_set_se_translator(&fSEHTranslator);
while(m_bDone)
{
DWORD dwResult;
DWORD dwBytes;
ULONG_PTR pHKey;
LPOVERLAPPED pOverlapped;
dwResult = GetQueuedCompletionStatus(m_hCP, &dwBytes, &pHKey, &pOverlapped, p_tickWait);
ICGExecutable* pExecuable = static_cast<ICGExecutable*>(pOverlapped);
pExecutable->ProcessExecute(dwResult, dwBytes);
pExecutable->Release();
}
}
SEH 와 C++ Exception 이 결합한다면 ?
IOCP Executor 의 처리를 try-catch 문으로 처리한다 .
try
{
pExecutable->ProcessExecute(dwResult, dwBytes);
}
catch(…)
{
}
참고 ) 성능을 위해 while 문에 try-catch 문은 최대한 빼도록 구현함 . try-catch 문을 밖으로 빼고 이중 while 문을 쓰는 것이 일반적임 .
예외처리
만약 , 이 함수 실행 중 ‘뻑’이 났다면…
이 ProcessExecute() 함수가 Strong Exception Guarantee 를 제공
하는 함수라면…
try-catch 블록으로 감싼다 .
8. CGCIICho sanghyun’s Game Classes II
CGCII 예외 시스템
CGCII 의 모든 Engine 시스템의 실행 처리는 CGCII 의 Execute System 하에서
동작을 하며 완벽한 Strong Exception Guarantee 를 보장한다 .
쉽게 말해서 아래와 같이 동작한다 .
1. 예외발생 정보 저장 .
2. Mini Dump 남김 .
3. 예외 알림 .
예외처리
9. CGCIICho sanghyun’s Game Classes II
CGCII 예외 처리
Pairing 처리를 해주어야 하는 것 !! 들
예외처리
예를 들어 접속 처리 과정에서 OnConnect() 가 정상적으로 호출되었다면 반드시
OnDisconnect() 가 호출되어야 한다 .
OnEnter() 함수가 호출되었으면 반드시 OnLeave() 함수가 호출되어야 한다 .
객체에 예외처리 전달
- Message 의 처리 과정에서 Message 처리 도중 전달되는 객체에도 예외처리 권한이
주어져야 한다 .
기타 등등…
원하는 시기에 원하는 대상에 원하는 내용의 예외를 처리할 수 있는 구조를 지원해주어야 한다
.
10. CGCIICho sanghyun’s Game Classes II
강제 예외 발생
강제 예외 발생 (Force Rasing Exception) 이란 강제로 예외를 발생 시키는 것 .
‘ 데드락’이나 ‘무한루프’에 빠진 쓰레드에 강제로 예외를 발생시켜 해결할 수 있다 .
다만 ! 예외 안전이 처리되었을 때만 제대로 처리 가능하다 . 그렇지 않다면 예외 발생시켜봐
야 어차피 엉망진창된다 .
Managed C++ 에는 이런 기능 있지만 Native C++ 에서는 직접 만들어야 된다 .
강제 예외 발생 구현은 시간 및 공간 제한 상 생략 ~
예외처리
#3:TLS를 사용하여 성능을 향상시킬 수 있다!!
아무리 Lock-Free라 해도 그냥 값을 복사하는 것보다는 성능이 확실히 떨어진다.
그래서 Lock의 최소화를 위해 TLS를 사용한다.
#4:생성하려는 객체는 반드시 ICGPoolable&lt;T&gt;를 상속받아야 한다.
사용할 때는 그냥 Alloc()함수를 호출하면 되고…
사용이 끝나게 되면 Free()함수를 호출하면 되는데 일반적으로 OnFinalRelease()함수에서 해준다.
#5:Windows의 기본 할당자와 CGPool의 성능을 비교한다.(Windows는 기본적으로 16Kbyte까지 LFH가 적용된다.)
#6:Object Pool은 객체의 할당을 위한 Pool이다.
사용방법은 매우 간단하다!!!
첫째 CGPool::CObject&lt;T&gt; 라고 하면 된다~~
그러면 그냥 Alloc(), Free()함수를 사용하여 객체의 할당과 할당해제를 수행할 수 있다
Pool 객체의 대상이 되는 객체는 무조건 ICGPoolable&lt;T&gt;을 상속받아야만 한다!!!
그리고 참조계수로 관리되므로 OnFinalRelease에 delete this가 아니라 Free(this)가 호출되어야 한다.
즉 다 사용되면 지워지는 것이 아니라 풀로 되돌려지는 것이다.
#7:생성하려는 객체는 반드시 ICGPoolable&lt;T&gt;를 상속받아야 한다.
사용할 때는 그냥 Alloc()함수를 호출하면 되고…
사용이 끝나게 되면 Free()함수를 호출하면 되는데 일반적으로 OnFinalRelease()함수에서 해준다.
#9:Alloc()/Free()를 사용하고 또 매번 OnFinalRelease()를 호출하도록 하려면 귀찬다.
따라서 NCGPoolable을 지원해준다.
#10:또 NCGPoolable&lt;T&gt;만 상속받았으면 NEW&lt;T&gt;로 생성한다면 자동으로 Pool에서 할당을 해준다.
#11:또 NCGPoolable&lt;T&gt;만 상속받았으면 NEW&lt;T&gt;로 생성한다면 자동으로 Pool에서 할당을 해준다.