Thinking Different







Synchronization Patterns : Scoped Locking - 동기화 패턴 : 범위 잠금


  • 선언된 스코프의 범위 내에서만 적용되는 동기화 디자인 패턴
  • 생성자, 소멸자 기능을 이용한 패턴으로써 동기화가 적용되는 범위를 스코프(범위)에서 사용되도록 한다






코드 다이어그램)


Lock 인터페이스를 정의하고 뮤텍스, 세마포어, 크리티컬 섹션 등을 상속받아 구현클래스를 정의하고, CGuard 클래스를 통해 Lock 클래스를 사용할 수 있도록 하였다.



소스코드)

Lock_Interface.h

1
2
3
4
5
6
7
8
9
10
11
12
13
#pragma once
 
class Lock_Interface
{
public:
    Lock_Interface() {}
    ~Lock_Interface(){}
public:
    inline virtual BOOL try_acquire(LONG timeOut = 0) = 0;
    inline virtual VOID acquire() = 0;
    inline virtual VOID release() = 0;
};
 


Mutex.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#pragma once
 
class Mutex : public Lock_Interface
{
public:
    Mutex() : m_hMutex(::CreateMutex(NULL, FALSE, NULL)) {}
    ~Mutex() { if (m_hMutex) CloseHandle(m_hMutex); }
public:
    inline VOID acquire() { WaitForSingleObject(m_hMutex, INFINITE); }
    inline VOID release() { ReleaseMutex(m_hMutex); }
    inline BOOL try_acquire(LONG timeOut = 0) { return WaitForSingleObject(m_hMutex, timeOut) == WAIT_OBJECT_0; }
private:
    HANDLE m_hMutex;
};


CriticalSection.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#pragma once
 
class CriticalSection : public Lock_Interface
{
public:
    CriticalSection() { InitializeCriticalSection(&m_CS); }
    ~CriticalSection() { DeleteCriticalSection(&m_CS); }
public:
    inline VOID acquire() { EnterCriticalSection(&m_CS); }
    inline VOID release() { LeaveCriticalSection(&m_CS); }
    inline BOOL try_acquire(LONG timeOut = 0) { return TryEnterCriticalSection(&m_CS); }
private:
    CRITICAL_SECTION m_CS;
};


Semaphore.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#pragma once
 
class Semaphore : public Lock_Interface
{
public:
    Semaphore(LONG min = 1, LONG max = 1) : m_hSemaphore(::CreateSemaphore(NULL, min, max, NULL)) {}
    ~Semaphore() { if (m_hSemaphore) CloseHandle(m_hSemaphore); }
public:
    inline VOID acquire() { WaitForSingleObject(m_hSemaphore, INFINITE); }
    inline VOID release() { ReleaseSemaphore(m_hSemaphore, 1, NULL); }
    inline BOOL try_acquire(LONG timeOut = 0) { return WaitForSingleObject(m_hSemaphore, timeOut) == WAIT_OBJECT_0; }
private:
    HANDLE m_hSemaphore;
};


CGuard.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#pragma once
 
template <typename T = CriticalSection>
class CGuard
{
public:
    CGuard(T* i) : mLock(i), bLocked(FALSE)
    {
        mLock->acquire();
        bLocked = TRUE;
    }
    ~CGuard() 
    {
        if (bLocked)
            mLock->release();
    }
private:
    T* mLock;
    BOOL bLocked;
};


main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//------------------------------------------------------------------
// 동기화 잠금 테스트 클래스
template<typename T>
class CTest
{
public:
    void ThreadSafe(int i)
    {
        CGuard<T> lock(&mlock);
        iData = i;
    }
 
private:
    int iData;
    mutable T mLock;
};
 
//------------------------------------------------------------------
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    CTest<CriticalSection> mTest;
    mTest.ThreadSafe(10);
 
    return 0;
}




static 키워드를 활용하여 Lock 멤버 내부에 숨기기)


위 소스에서 보듯이, 스레드 동기화가 필요한 클래스에서는 Lock 구현 객체가 반드시 내부에 선언되어 그 객체를 CGuard 동기화 처리 되는 부분에 항상 포인터로 넘겨주어야 하는 부분이 필요했었다. 이 부분을 상위 클래스의 내부 static 멤버로 숨겨서 깨끗하게 처리하는 패턴이다. ( 원본 소스 출처(1) : 정보문화사 - 온라인 게임 서버 프로그래밍 )

이 패턴은 출처(1) 소스에서 변경하여 적용한 예제이다.


예제 코드) Lock 인터페이스 이하 구현 클래스는 동일하므로 제외하도록 한다

MultiThreadSync.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#pragma once
 
template <typename T, typename LOCK = CriticalSection>
class CMultiThreadSync
{
public:
    class CThreadSync
    {
    public:
        CThreadSync(VOID) : bLocked(FALSE)
        {
            T::mSync.acquire();
            bLocked = TRUE;
        }
 
        ~CThreadSync(VOID)
        {
            if (bLocked)
                T::mSync.release();
        }
 
    private:
        BOOL bLocked;
    };
 
private:
    static LOCK mSync;
};
 
template <typename T, typename LOCK = CriticalSection>
LOCK CMultiThreadSync<T, LOCK>::mSync;


main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//------------------------------------------------------------------
// 동기화 잠금 테스트 클래스
class CTest : CMultiThreadSync<CTest>
{
public:
    void ThreadSafe(int i)
    {
        CThreadSync cs;
        iData = i;
    }
 
private:
    int iData;
};
 
//------------------------------------------------------------------
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    CTest mTest;
    mTest.ThreadSafe(10);
 
    return 0;
}