C ++의 효율적인 스레드로부터 안전한 싱글 톤
싱글 톤 클래스의 일반적인 패턴은 다음과 같습니다.
static Foo &getInst()
{
static Foo *inst = NULL;
if(inst == NULL)
inst = new Foo(...);
return *inst;
}
그러나 1) Foo의 생성자가 두 번 이상 호출 될 수 있고 (중요하지 않을 수도 있음) 2) inst가 다른 스레드로 반환되기 전에 완전히 생성되지 않을 수 있기 때문에이 솔루션은 스레드로부터 안전하지 않다는 것을 이해합니다. .
한 가지 해결책은 전체 메서드에 뮤텍스를 래핑하는 것이지만, 실제로 필요한 시점 이후에 동기화 오버 헤드에 대한 비용을 지불합니다. 대안은 다음과 같습니다.
static Foo &getInst()
{
static Foo *inst = NULL;
if(inst == NULL)
{
pthread_mutex_lock(&mutex);
if(inst == NULL)
inst = new Foo(...);
pthread_mutex_unlock(&mutex);
}
return *inst;
}
이것이 올바른 방법입니까, 아니면 제가 알아야 할 함정이 있습니까? 예를 들어, 발생할 수있는 정적 초기화 순서 문제가 있습니까? 즉, getInst가 처음 호출 될 때 inst가 항상 NULL임을 보장합니까?
귀하의 솔루션은 '이중 검사 잠금'이라고하며 작성한 방식은 스레드 안전하지 않습니다.
이 Meyers / Alexandrescu 논문은 그 이유를 설명하지만, 그 논문도 널리 오해되고 있습니다. '더블 체크 잠금은 C ++에서 안전하지 않다'라는 밈을 시작했지만 실제 결론은 C ++에서 이중 체크 잠금을 안전하게 구현할 수 있다는 것이며, 분명하지 않은 장소에서 메모리 장벽을 사용하면됩니다.
이 문서에는 메모리 장벽을 사용하여 DLCP를 안전하게 구현하는 방법을 보여주는 의사 코드가 포함되어 있으므로 구현을 수정하는 것이 어렵지 않습니다.
C ++ 11을 사용하는 경우이를 수행하는 올바른 방법은 다음과 같습니다.
Foo& getInst()
{
static Foo inst(...);
return inst;
}
새로운 표준에 따르면 더 이상이 문제에 대해 신경 쓸 필요가 없습니다. 객체 초기화는 한 스레드에서만 이루어지며 다른 스레드는 완료 될 때까지 대기합니다. 또는 std :: call_once를 사용할 수 있습니다. ( 여기에 자세한 정보 )
Herb Sutter는 CppCon 2014의 이중 확인 잠금에 대해 이야기합니다.
다음은이를 기반으로 C ++ 11에서 구현 한 코드입니다.
class Foo {
public:
static Foo* Instance();
private:
Foo() {}
static atomic<Foo*> pinstance;
static mutex m_;
};
atomic<Foo*> Foo::pinstance { nullptr };
std::mutex Foo::m_;
Foo* Foo::Instance() {
if(pinstance == nullptr) {
lock_guard<mutex> lock(m_);
if(pinstance == nullptr) {
pinstance = new Foo();
}
}
return pinstance;
}
여기에서 전체 프로그램을 확인할 수도 있습니다 : http://ideone.com/olvK13
pthread_once초기화 함수가 원자 적으로 한 번 실행되도록 보장하는을 사용하십시오 .
(Mac OS X에서는 스핀 잠금을 사용합니다. 다른 플랫폼의 구현을 모릅니다.)
잠금없이이를 수행하는 유일한 스레드 안전 방법 인 TTBOMK 는 스레드를 시작 하기 전에 모든 싱글 톤을 초기화하는 것 입니다.
Your alternative is called "double-checked locking".
There could exist multi-threaded memory models in which it works, but POSIX does not guarantee one
ACE singleton implementation uses double-checked locking pattern for thread safety, you can refer to it if you like.
You can find source code here.
Does TLS work here? https://en.wikipedia.org/wiki/Thread-local_storage#C_and_C++
For example,
static _thread Foo *inst = NULL;
static Foo &getInst()
{
if(inst == NULL)
inst = new Foo(...);
return *inst;
}
But we also need a way to delete it explicitly, like
static void deleteInst() {
if (!inst) {
return;
}
delete inst;
inst = NULL;
}
The solution is not thread safe because the statement
inst = new Foo();
can be broken down into two statements by compiler:
Statement1: inst = malloc(sizeof(Foo));
Statement2: inst->Foo();
Suppose that after execution of statement 1 by one thread context switch occurs. And 2nd thread also executes the getInstance() method. Then the 2nd thread will find that the 'inst' pointer is not null. So 2nd thread will return pointer to an uninitialized object as constructor has not yet been called by the 1st thread.
참고URL : https://stackoverflow.com/questions/2576022/efficient-thread-safe-singleton-in-c
'Nice programing' 카테고리의 다른 글
| Firefox와 Opera가 디스플레이 내부의 최대 너비를 무시하는 이유 : 테이블 셀? (0) | 2020.11.10 |
|---|---|
| navbar 상단의 Twitter-Bootstrap-2 로고 이미지 (0) | 2020.11.10 |
| 바로 가기 키로 Chrome 콘솔을 지우는 방법은 무엇입니까? (0) | 2020.11.10 |
| catch 및 finally에서 return 문 동작 (0) | 2020.11.10 |
| ng-repeat를 사용하여 AngularJS에서 맵 항목을 반복하는 방법 (0) | 2020.11.10 |