art.oriented에 놀러 갔다가 답글을 달았는데, 별 생각 없이 "상호작용하는 함수에서 빠져나올때 자신이 사용한 동기화 객체를 초기화하는 부분이 따라오는게 맞겠죠."라는 말을 썼다.
언젠가 당한적이 있으니 저런 소리를 했을텐데하고 생각을 해보니 꽤나 오래전에 삽질했던 기억이 난다. 5~6년은 된 일인듯. 그때 상황이 정확히 기억날리는 당연히 없고, 대략 비슷하게 만들면 다음과 같다.
// Example
class CCriticalSection
{
public:
CCriticalSection() { InitializeCriticalSection(&m_cs); }
~CCriticalSection() { DeleteCriticalSection(&m_cs); }
void Enter() { EnterCriticalSection(&m_cs); }
void Leave() { LeaveCriticalSection(&m_cs); }
private:
CRITICAL_SECTION m_cs;
};
unsigned __stdcall ThreadFunc(void* param)
{
CCriticalSection* pcs = static_cast<CCriticalSection*>(param);
pcs->Enter();
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
CCriticalSection* pcs = new CCriticalSection;
pcs->Enter();
uintptr_t handle = _beginthreadex(NULL, 0, ThreadFunc,
(void*)pcs, 0, NULL);
Sleep(100);
delete pcs; // lock 상태에서 그냥 삭제
WaitForSingleObject((HANDLE)handle, INFINITE);
printf("Thread terminated.");
return 0;
}
대부분은 그냥 그런 코드고 실제 문제가 됐던 부분은 주석이 달린 저 부분이다. CRITICAL_SECTION이 lock된 상태에서 개체를 삭제해버린 저 문제 말이다. CCriticalSection의 소멸자가 호출돼 CRITICAL_SECTION을 해제하기때문에 리소스 릭은 없지만 ThreadFunc을 빠져 나올 방법은 없다(데드락).
삭제라는 복잡한 방법을 썼지만 delete pcs의 위치에서 CRITICAL_SECTION을 해제(DeleteCriticalSection())해도 결과는 같다(사실 코드도 거의 같다).
교훈은 하나다. 동기화 오브젝트를 삭제(해제)해야 한다면 현재 상태를 반드시 확인하고 꼭 풀어 줘야한다. 아니면 좋지 않다.
ps. 동기화 객체를 삭제하면 락을 다 해제하고 자폭하는게 직관적이라고 생각하는 사람은 나뿐일까...
TAG Programming
