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. 동기화 객체를 삭제하면 락을 다 해제하고 자폭하는게 직관적이라고 생각하는 사람은 나뿐일까...

Posted by 조성경 트랙백 0 : 댓글 0