2014-12-31 3 views
1

싱글 톤이 스레드에 안전하지 않다고 읽었습니다. 나는 이것이 왜 있는지 이해하려고 노력하고 있습니다. 나는이 같은 단일 개체가있는 경우 :싱글 톤 스레드가 안전하지 않은 이유는 무엇입니까?

class singleton final 
{ 
public: 
    static singleton& instance() 
    { 
     static singleton unique; 
     return unique; 
    } 
private: 
    singleton() = default; 
    singleton(singleton const&) = delete; 
    singleton& operator=(singleton const&) = delete; 
}; 

을 그리고 난 같은 코드가있는 경우 :

singleton *p1, *p2; 

auto t1 = std::thread([] { p1 = &singleton::instance(); }); 
auto t2 = std::thread([] { p2 = &singleton::instance(); }); 

t1.join(); 
t2.join(); 

그것이 p1p2 가능한가 두 개의 서로 다른 singleton 인스턴스를 가리 키도록? uniquestatic 인 경우 "정적"특성이 완전히 초기화 될 때까지 영향을 미치지 않습니까? 그렇다면 정적 객체의 초기화를 동시에 액세스 할 수 있으므로 여러 정적 객체를 만들 수 있습니까? 접두사 이름 컴파일러가있다 -은 "__"이

bool __instance_initialized = false; 
alignas(X) char __buf_instance[sizeof(X)]; 
// ... 
X& instance() 
{ 
    if (!__instance_initialized) 
    { 
     ::new(__buf_instance) X; 
     __instance_initialized = true; 
    } 
    return *static_cast<X*>(__buf_instance); 
} 

:

X& instance() 
{ 
    static X x; 
    return x; 
} 

이 코드가 같은 것을 할 것이라는 점을 의미한다 : C++ 98/03 파일 현지 정적에서

+2

정적 초기화 규칙이 C++ 11에서 스레드 안전성이 변경되었습니다. – Jarod42

+0

@ Jarod42 알아 두지 만 왜 스레드로부터 안전하지 않은지 이해하고 싶습니다. –

+0

아직 하나의 객체가 있지만 초기화가 스레드 안전하지 않습니다. 초기화되지 않은 객체를 반환하는 것은 발생할 수 있습니다 (이중 초기화는 확실하지 않습니다) – Jarod42

답변

11

제공됩니다.

위 코드에서 두 스레드가 동시에 if에 들어가는 것을 막을 수는 없으며 두 시간 모두 X을 동시에 작성하려고 시도하지 않습니다. 컴파일러는 서면으로 그 문제를 해결하기 위해 시도 할 수 있습니다 :

bool __instance_initialized = false; 
alignas(X) char __buf_instance[sizeof(X)]; 
// ... 
X& instance() 
{ 
    if (!__instance_initialized) 
    { 
     __instance_initialized = true; 
     ::new(__buf_instance) X; 
    } 
    return *static_cast<X*>(__buf_instance); 
} 

을하지만 하나 개의 스레드가 true로 __instance_initialized을 설정하고 X를 구성하는 시작하고, 두 번째 스레드 테스트를하고있는 동안 if을 건너하는 지금이 가능합니다 첫 번째 스레드는 여전히 X을 생성하는 중입니다. 그런 다음 두 번째 스레드는 첫 번째 스레드가 마지막으로 구성을 완료 할 때까지 클라이언트에 초기화되지 않은 메모리를 제공합니다.

C++ 11에서는 컴파일러가 두 번째 스레드가 실행되지 않도록 코드를 설정하고 첫 번째 스레드가 성공적으로 완료 될 때까지 X의 구성을 시작해야합니다. 이것은 첫 번째 쓰레드가 끝날 때까지 두 번째 쓰레드가 임의의 시간 동안 기다려야 만 진행될 수 있음을 의미합니다. X을 생성하는 동안 첫 번째 스레드가 예외를 throw하면 두 번째 스레드가 깨어나서이를 구성합니다.

Here is the Itanium ABI specification 컴파일러가 어떻게 수행 할 수 있는지.

+0

이제 완벽하게 이해할 수 있습니다. 감사. –

관련 문제