2009-06-27 4 views
13

메서드 내에서 선언 된 정적 변수가 스레드로부터 안전하지 않다는 것을 기억합니다.뮤텍스가없는 스레드 안전 정적 변수?

Dog* MyClass::BadMethod() 
{ 
    static Dog dog("Lassie"); 
    return &dog; 
} 

내 라이브러리가 응용 프로그램의 일부로 컴파일 최종 사용자를위한 C++ 코드를 생성 (Todd Gardner에서 언급 한 바와 같이 What about the Meyer's singleton? 참조). 생성 된 코드는 스레드로부터 안전한 크로스 플랫폼 방식으로 정적 변수를 초기화해야합니다. 변수 초기화를 뮤텍스하기 위해 boost::call_once을 사용하고 싶지만 최종 사용자는 부스트 의존성에 노출되어 있습니다.

최종 사용자에게 추가 의존성을 강요하지 않으면이 작업을 수행 할 수있는 방법이 있습니까?

+0

부스트 라이브러리를 정적으로 직접 링크 할 수도 있습니다. 그런 다음 사용자가 불편을 겪을 염려없이 부스트 라이브러리를 사용할 수 있습니다. – Ben

+0

[C++ 11에서는 로컬 정적 변수 초기화가 스레드 안전합니까?] (http://stackoverflow.com/questions/8102125/is-local-static-variable-initialization-thread-safe-in-c11) –

+1

@ LucianAdrianGrijincu,이 질문은 C++ 11 이전 (2009 년 게시되었습니다)이므로 귀하의 질문은 엄격한 복제는 아니지만 관련이 있습니다. 링크를 가져 주셔서 감사합니다. – Gili

답변

10

당신은 초기화 할 표준, 스레드 안전, 휴대용 방법은 없습니다, 순간

(here는 컴파일러로 돌려 무슨 토론 기사입니다) 같은 정적 초기화가 스레드로부터 안전하지 않습니다 것을 올바른지 정적 싱글 톤. 이중 검사 잠금을 사용할 수 있지만 잠재적으로 휴대용이 아닌 스레드 라이브러리가 필요합니다 (토론 here 참조).

  1. 이 게으른하지 말라 (로드) : 정적 초기화시에 초기화 스레드 안전이 필수 인 경우

    여기에 몇 가지 옵션이 있습니다. 정적 초기화 순서가 정의되지 않았기 때문에 다른 정적 함수가이 함수를 생성자에서 호출하면 문제가 될 수 있습니다 (here 참조).지원되는 플랫폼 에

  2. 사용 (당신이 말한대로) 부스트 또는 로키
  3. 롤 당신의 자신의 싱글은
  4. 잠금 액세스를 필요로 뮤텍스마다 (아마 하지 않는 한 당신이 스레딩 전문가이다 피해야한다). 이것은 매우 느릴 수 있습니다.

예 1 :

// in a cpp: 
namespace { 
    Dog dog("Lassie"); 
} 

Dog* MyClass::BadMethod() 
{ 
    return &dog; 
} 

예 4 :

Dog* MyClass::BadMethod() 
{ 
    static scoped_ptr<Dog> pdog; 
    { 
    Lock l(Mutex); 
    if(!pdog.get()) 
     pdog.reset(new Dog("Lassie")); 
    } 
    return pdog.get(); 
} 
+0

총알을 물고 끝내고 boost :: call_once()를 사용했습니다. – Gili

+7

이 답변은 현재 사용되지 않습니다. http://stackoverflow.com/questions/8102125/is-local-static-variable-initialization-thread-safe- in-c11 – Yankes

2

나는 당신이 당신의 "static Dog" 같은 비보호 자원 스레딩 문제가되지 않습니다 보장하기 위해 알고있는 유일한 방법은 그들이 전혀 스레드가 생성 전에 을 인스턴스화하고 요구하는 것입니다.

다른 작업을 수행하기 전에 기본 스레드에서 MyInit() 함수를 호출해야한다는 것을 문서화하는 것만 큼 간단 할 수 있습니다. 그런 다음 MyInit()을 생성하여 이러한 통계 중 하나를 포함하는 각 유형의 객체 하나를 인스턴스화하고 파기하십시오.

유일한 대안은 생성 된 코드를 어떻게 사용할 수 있는지에 대한 또 다른 제한을 두는 것입니다 (Boost, Win32 threads 등 사용). 이러한 솔루션 중 하나는 제 의견으로는 받아 들일 수 있습니다. 따라야하는 규칙을 생성하는 것은 괜찮습니다.

문서에 명시된 규칙을 따르지 않을 경우 모든 배팅이 해제됩니다. 초기화 함수를 부르거나 Boost에 의존해야한다는 규칙은 나에게 부당하지 않습니다.

static Dog dog("Lassie"); 
Dog* MyClass::BadMethod() 
{ 
    return &dog; 
} 

Dog 인스턴스가 메인 스레드 전에 초기화됩니다 스레드 안전을 위해 뮤텍스가 필요하지 않습니다 당신이 그것을 할 수

3

한 가지 방법은 오히려 정적 기능보다는 정적 싱글에게 파일을 만드는 것입니다 실행됩니다. 파일 정적 변수는 초기화 순서와 관련하여 유명한 문제가 있지만 개가 다른 번역 단위에 정의 된 다른 정적에 의존하지 않는 한 이는 중요하지 않습니다.

+0

Windows의 DLL에 전역 초기화 프로그램이있는 경우 문제가 발생할 수 있습니다. 그러나 구체적인 내용은 기억할 수 없으며 코드가 DLL에있는 경우에만 실제로 관련이 있습니다. D – olliej

+0

내 코드 *에 상주합니다. DLL을 : 무슨 문제를 알고 있어야합니까? 내가 알고있는 한 – Gili

+0

. 내 최고의 추측은 DLL이로드 될 때마다 한 번씩 실행되는 생성자이므로 dll이 언로드되고 다시로드되면 다시 생성되므로 Singleton의 "계약"이 깨지기 때문에 그 정도는 할 수 있습니다. –

2

AFAIK이 안전하게 수행 뮤텍스 또는 글로벌 인스턴스의 사전 초기화 마태 복음에없는되어있는 유일한 시간 Wilson의 Imperfect C++에는 "스핀 뮤텍스"를 사용하여이를 수행하는 방법이 설명되어 있습니다. 나는 그것의 사본에 가까이 있지 않으므로,이 시점에서 더 이상 당신을 말할 수는 없다.

IIRC이 시간에 어떤 구성 요소가 기억 나지는 않지만 STLSoft 라이브러리 내부에서이를 사용하는 몇 가지 예가 있습니다.

4

이것이 의미하는 것인지 확실하지 않지만 대신 pthread_once을 호출하여 POSIX 시스템의 부스트 종속성을 제거 할 수 있습니다. 윈도우즈에서 뭔가 다른 것을 해봐야 할 것 같지만 그것이 왜 부스트가 처음에는 쓰레드 라이브러리를 갖고 있는지와 왜 사람들이 그것에 의존하는 댓가로 돈을 지불 하는지를 피하는 것입니다.

"thread-safeely"하는 것은 본질적으로 스레드 구현에 묶여 있습니다. 에 의존해야하는데, 플랫폼 종속 메모리 모델 인 경우에도 마찬가지입니다. 순수 C++ 03에서는 언어의 범위를 벗어나는 쓰레드에 대해 전혀 고려하지 않는 것이 가능합니다.