동기화 패턴 : 스레드 안전 인터페이스(Synchronization Patterns : Thread Safe Interface)
Gof Design Pattern2014. 2. 21. 08:03
Synchronization Patterns : Thread Safe Interface - 동기화 패턴 : 스레드 안전 인터페이스
- 멀티스레드 프로그래밍 중에서 클래스 내부의 메서드 호출로 발생되는 셀프 데드락(Self-Dead lock) 현상 방지를 위한 패턴이다.
- 동기화에 필요한 공개함수와 내부에서 사용될 내부 함수를 분리하고, 외부에서 접근하는 공개함수들에 대해서만 동기화하고 내부 함수를 세분화하여 접근하도록 한다.
동기화와 셀프 데드락(Self-Dead lock)이란?
- 동기화 : 다수의 스레드가 하나의 리소스에 대해서 동시에 접근할 경우 다른 스레드가 변경한 리소스를 또 다른 스레드가 덮어쓰거나 변경시켜버릴 가능성이 있다(Race condition). 이를 보호하기 위해서 동기화라는 작업을 통해서 적절히 공유된 리소스를 접근할때에는 하나의 스레드만 접근되도록 하는 것이다.
- 데드락 : 멀티 스레드 환경에서 어떤 스레드도 리소스에 더이상 접근이 불가능한 상태를 일컫는다.
- 셀프 데드락 : 멀티 스레드 환경에서 어떤 스레드가 이미 자신이 선점한 리소스 동기화 락을 다시 얻으려고 할때 발생된다.
Self-Dead lock 발생 코드 예제)
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 32 33 34 35 36 37 38 39 40 41 42 43 44 | #include <list> class CTest { public: CTest(int i) : m_Id(i) {} int GetId() const { return m_Id; } private: int m_Id; }; class CTestManager : public CMultiThreadSync<CTestManager> { public: ~CTestManager() { for each (CTest* var in mList) delete var; mList.clear(); } public: void insert(CTest* i) { CThreadSync cs; // 첫번째 스코프 동기화 if (!search(i)) mList.push_back(i); else delete i; } bool search(CTest* i) { CThreadSync cs; // 두번째 스코프 동기화 for each (CTest* var in mList) { if (var->GetId() == i->GetId()) return true; } return false; } private: list<CTest*> mList; }; |
- Insert 함수를 통해 CTest 객체를 추가한다.
- Insert 함수 내부에서 먼저 멀티스레드 락 방지로 스코프 동기화를 해주고, 컨테이너에 객체가 이미 존재하는지 검사 후 없다면 추가하도록 한다.
- 여기서 문제점은 최초 insert 함수 호출시 스코프 동기화를 걸고 락이 해제되기 전에 search 함수 호출로 다시 내부에서 동기화 락을 얻는 과정에서 셀프 데드락이 발생된다.
수정 코드 다이어그램)
다이어그램에서 보듯이, insert 와 search함수들을 외부함수, 내부함수로 세분화하고 외부함수에만 스코프 동기화를 걸어주어 셀프 데드락을 해결하였다.
수정 소스 코드)
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | #include <list> //------------------------------------------------------------------ // CTest Entity 클래스 class CTest { public: CTest(int i) : m_Id(i) {} int GetId() const { return m_Id; } private: int m_Id; }; //------------------------------------------------------------------ // CTestManager 클래스 <스코프 동기화> class CTestManager : public CMultiThreadSync<CTestManager> { public: CTestManager() {} ~CTestManager() { for each (CTest* var in mList) delete var; mList.clear(); } public: void insert(CTest* i) { CThreadSync cs; insert_i(i); } bool search(CTest* i) { CThreadSync cs; return search_i(i); } private: void insert_i(CTest* i) { if (!search_i(i)) mList.push_back(i); } bool search_i(CTest* i) { for each (CTest* var in mList) { if (var->GetId() == i->GetId()) return true; } return false; } private: list<CTest*> mList; }; //------------------------------------------------------------------ // Main int _tmain(int argc, _TCHAR* argv[]) { CTestManager mTestManager; mTestManager.insert(new CTest(1024)); return 0; } |
'Gof Design Pattern' 카테고리의 다른 글
싱글톤 패턴 (Singleton Pattern) (0) | 2014.03.06 |
---|---|
동기화 패턴 : 범위 잠금 (Synchronization Patterns : Scoped Locking) (0) | 2014.02.21 |
풀링 패턴 (Pooling Pattern) (1) | 2014.02.12 |
해석자 패턴 (Interpreter Pattern) (0) | 2014.02.08 |
방문자 패턴 (Visitor Pattern) (0) | 2014.02.04 |