[C++] DCLP - Double-Checked Locking Pattern
DCLP
Double-Checked Locking Pattern
GOF의 23가지 패턴 중 싱글톤 패턴 (Singleton Pattern) 에서 사용하는 패턴 입니다.
단일로 사용하는 패턴은 아니고 싱글톤 패턴의 단점을 보완해주는 역할을 하게 되죠
2015/12/17 - [Development/Design Pattern] - [C++] 싱글톤 패턴 - Singleton Pattern
이전 글 에서 보면 안전해보이고 문제가 없을 것 같지만 멀티쓰레드 환경에서는 Thread safe 이슈가 있습니다.
바로 싱글톤 패턴의 핵심인 단일 인스턴스의 생성이 보장되지 않는다는것이죠
static singleton* instance() {
if (_instance == nullptr) {
_instance = new singleton();
}
return _instance;
}
자 다음과 같은 코드가 있습니다.
당연히 사용자는 singleton::instance()->function() 이런식으로 접근을 할 것 입니다.
이때 1번 Thread가 요청합니다.
아직 생성되지 않았기때문에 _instance가 nullptr 입니다. 그래서 _instance = new singleton() 을 호출하려 합니다.
이 때!
OS가 인터럽트를 걸고 2번 Thread에게 제어권을 넘깁니다.
아직 _instance는 nullptr 입니다
2번 Thread에서 _instance = new singleton(); 을 호출하여 메모리가 생성되었네요
그런데!
OS가 1번 Thread에게 제어권을 넘기게 되니 또 하나의 _instance가 생성되버리고 말았습니다.
이렇게 되면 Singleton Pattern의 핵심인 단일 instance여야 한다는 규칙이 깨지게 되었고 메모리 Leak이 발생하게 된 것 입니다.
그런 이유로 해당 문제를 해결하기 위해 DCLP 가 나온 것 입니다.
example
class singleton {
private:
static singleton* _instance;
static std::mutex _mutex;
singleton() {}
singleton(const singleton& other);
~singleton() {}
public:
static singleton* instance() {
if (_instance == nullptr) {
std::lock_guard<std::mutex> lock(_mutex);
if (_instance == nullptr) {
_instance = new singleton();
}
}
return _instance;
}
};
위처럼 2번 체크하면서 락을 건다 해서 Double-Checked Locking Pattern 이라고 하는 것 같습니다.
여기서 Locking은 RAII 패턴으로 적용하였습니다.
하지만 여전히 문제를 앉고있습니다. 상황에 따라 컴파일러에서 최적화가 되어버리면 의도치 않게 동작할 수도 있기 때문입니다.
* 컴파일러 최적화에 의해 생성자가 호출되지 않았음에도 불구하고 _instance가 할당되어 사용되는 상황이 발생하여 버릴 수 있습니다.
이 때 적용할 수 있는게 volatile 입니다.
C/C++ 프로그래밍 언어에서 이 키워드는 최적화 등 컴파일러의 재량을 제한하는 역할을 한다고 합니다.
WIKI - https://ko.wikipedia.org/wiki/Volatile_%EB%B3%80%EC%88%98
Volatile이 적용된 example
class singleton {
private:
static singleton* volatile _instance;
static std::mutex _mutex;
singleton() {}
singleton(const singleton& other);
~singleton() {}
public:
static singleton* volatile instance() {
if (_instance == nullptr) {
std::lock_guard<std::mutex> lock(_mutex);
if (_instance == nullptr) {
_instance = new singleton();
}
}
return _instance;
}
};
그래도 조금은 다듬어진 코드가 완성되었네요
위 코드는 문제점을 조금이나마 줄이기 위하여 많은 사람들이 생각하고 또 생각한 방법 중 하나입니다.
여러가지 기법이 있겠지만 가장 간단한 방법이라 소개드리고싶네요
글을 작성하다보니 위의 _instance를 그냥 포인터가 아닌 스마트포인터인 std::shared_ptr을 사용하면 어떨까 생각이 드네요~
또 싱글톤 클래스의 생성이 그렇게 부담스럽지 않다면 Main Initialize() 하는곳에서 각각 초기화를 해놓는건 어떨까요??
여러가지 방법이 있고 여러가지 생각을 할 수 있어 공부하기 좋은 패턴인 것 같습니다!!
감사합니다.
'⌨ DEVELOPMENT > Design Pattern' 카테고리의 다른 글
[C++] 싱글톤 패턴 - Singleton Pattern (0) | 2015.12.17 |
---|---|
[C++] RAII 패턴 - Resource Acquisition Is Initialization Pattern (0) | 2015.12.16 |
댓글
이 글 공유하기
다른 글
-
[C++] 싱글톤 패턴 - Singleton Pattern
[C++] 싱글톤 패턴 - Singleton Pattern
2015.12.17 -
[C++] RAII 패턴 - Resource Acquisition Is Initialization Pattern
[C++] RAII 패턴 - Resource Acquisition Is Initialization Pattern
2015.12.16