2014-11-16 6 views
3

는 C++ 11에서 싱글 구현하는 스레드 안전한 방법입니다 다음 알고 I : 또한 스레드 -스레드 안전 싱글은 C++ 11

Foo* getInst() 
{ 
    static Foo* inst = new Foo(...); 
    return inst; 
} 

내가 다음 this answer 읽을입니다 안전 :

Foo& getInst() 
{ 
    static Foo inst(...); 
    return inst; 
} 

정말 스레드로부터 안전합니까?
Foo 의 인스턴스가 단일 스택 프레임에 할당되는 것이 문제가되지 않습니까? 은 힙에 할당되지 않습니까?

스레드로부터 안전 할 경우 다른 것을 선호하는 이유가 무엇입니까?

+0

* 두 변수 모두 정적이므로 동일한 수명 시맨틱을 의미하므로 두 번째 변수가 안전하지 않으면 첫 번째 변수도 안전하지 않습니다. – cdhowie

+2

정적 초기화는 C++ 11에서 스레드로부터 안전하다는 점에 유의하십시오. 이전 버전의 표준에서는 이러한 보증을하지 않습니다. 또한, MSVC2012 및 2013에서 정적 초기화에는 버그가 포함되어 있으며 실제로는 스레드로부터 안전하지 않습니다. 크로스 플랫폼 코드의 경우 마술 정체를 사용하지 않기위한 조언이 필요합니다. – Stefan

답변

9

정적 변수는 아니요 스택에 할당 된입니다. 첫 번째 변형에는 힙에서 가져온 메모리로 초기화 된 정적 포인터 (전역 변수)가 있고 두 번째 변형에서는 전체 정적 객체가 있습니다.

두 버전 모두 글로벌 인스턴스가 이미 초기화되지 않았거나 여부를 알려주는 특별한 변수에 직렬화 된 액세스를 보장하기 위해 (기능적 mutex::lock()mutex::unlock() 동등 즉 __cxa_guard_acquire()__cxa_guard_release()) 내부 컴파일러 가드를 사용합니다.

귀하의 코드 :

Foo& getInst() 
{ 
    static Foo inst(...); 
    return inst; 
} 

실제로 컴파일 후 그 모양을 : 당신의 exampes의 그래서

Foo& getInst() 
{ 
    static Foo inst; // uninitialized - zero 
    static guard instGuard; // zero 

    if (is_initialized(instGuard) == false) 
    { 
     __cxa_guard_acquire(instGuard); 
     // do the initialization here - calls Foo constructor 
     set_initialized(instGuard); 
     __cxa_guard_release(instGuard); 
    } 

    return inst; 
} 

모두 스레드로부터 안전합니다.

+0

그래서 스레드로부터 안전합니까? – Kaveh

+0

@Kaveh - 첫 번째 버전만큼 안전합니다. 좀 더 정확하게하려면 잠시 후에 대답을 편집하겠습니다. –

+0

표준을 검사했습니다. 정적 멤버는 기본적으로 쓴 것처럼 작동합니다 (thread_local로 선언되지 않으면 모든 스레드에 대해 단일 인스턴스가됩니다). – Kaveh

4

inst은 스택에 할당되지 않습니다. .data 또는 .bss 섹션에 할당됩니다. 그렇지 않으면이 정적 변수는 프로그램이 실행될 때마다 살아갈 수 없으므로이 함수를 입력 할 때마다 이전과 같은 값을 가질 수 없습니다.