2016-09-12 1 views
1

입니다. this에 C++의 Double Checked Locking Pattern에 대한 기사가 있습니다. 저자는 volatile을 사용하여 DCLP를 "올바르게"구현하려는 시도 중 하나를 시연했습니다 (10 페이지). 변수 : 텍스트 조각이C++에서 Double Checked Locking을 구현하는 방법은

class Singleton { 
public: 
    static volatile Singleton* volatile instance(); 

private: 
    static volatile Singleton* volatile pInstance; 
}; 

// from the implementation file 
volatile Singleton* volatile Singleton::pInstance = 0; 
volatile Singleton* volatile Singleton::instance() { 
    if (pInstance == 0) { 
    Lock lock; 
    if (pInstance == 0) { 
     volatile Singleton* volatile temp = new Singleton; 
     pInstance = temp; 
    } 
    } 
    return pInstance; 
} 

예 후는 이해가되지 않는 :

관찰 행동에 표준의 제약이 역으로 정의 추상 기계만을위한 첫째,

그 추상 기계 에는 다중 스레드 실행 개념이 없습니다. 재정렬 읽고 휘발성 데이터 내 스레드가, 모든에 같은 reorderings 에서 스레드에서 제약 조건을 부과하지 않습니다에 기록에서 그 결과, 불구하고 표준 컴파일러를 방지 할 수 있습니다. 최소한 컴파일러 구현자가 대부분 해석하는 방법입니다. 결과적으로 실제로 많은 컴파일러가 위 소스에서 스레드 안전하지 않은 코드를 생성 할 수 있습니다.

이상 :

... C++의 추상 기계는 단일 스레드이며, C++ 컴파일러는 어쨌든 위, 같은 소스에서 스레드 안전하지 않은 코드를 생성 할 수도 있습니다.

이러한 설명은 유니 프로세서에서의 실행과 관련되어 있으므로 캐시 일관성 문제는 아닙니다.

순서를 변경할 수 없습니다 컴파일러가 읽고 휘발성 데이터 스레드 내에서 에 쓰는 경우

, 어떻게 할 수는 재주문 읽기 때문에 스레드 안전하지 않은 코드를 생성이 특정 예를 들어 에서 스레드를 쓴다?

volatile Singleton* volatile temp = new Singleton; 
pInstance = temp; 

속으로 :

+0

그 기사는 2004 년 이후로, C++ 11 및 그 업데이트 된 추상 기계보다 상당히 오래된 것입니다. – molbdnilo

+0

@molbdnilo 알았어.하지만 컴파일러가 _across_ 쓰레드를 읽고 쓰는 순서를 어떻게 설명 할 수 있니? – undermind

답변

0

나는 그들이 단일 스레드 추상 기계의 맥락에서 컴파일러가 간단하게 변환 할 수 있다는 말을 제대로 이해 해요 경우

pInstance = new Singleton; 

관찰 행동 때문에 변경되지 않았습니다. 그러면 이중 확인 잠금으로 원래의 문제로 되돌아갑니다. 값이되기 전에

+0

그러나 나는 'volatile'을 사용하는 것이 컴파일러가 여러분이 언급 한 최적화를하지 못하게한다고 생각했습니다. C++ 03 Standard 1.9.6에 따르면 : "추상 기계의 관찰 가능한 동작은 라이브러리의 I/O 기능에 대한"volatile "데이터 및 호출에 대한 읽기 및 쓰기 시퀀스와 1.9.7입니다. a 'volatile' lvalue, 객체 수정 중 ... 부작용이 있습니다 ... 특정 지정 포인트 ...이전 평가의 모든 부작용이 완료되고 후속 평가의 부작용이 발생하지 않아야합니다. " – undermind

1

나는 그들이 제 6 조 ("DCLP에 다중 기계"에 설명 된 캐시 일관성 문제를 참조하고 생각합니다. 멀티 프로세서 시스템으로, 프로세서/캐시 하드웨어는 pInstance의 값을 쓸 수 있습니다 할당 된 Singleton에 대해 쓰여지므로 두 번째 CPU가 가리키는 데이터를보기 전에 NULL이 아닌 pInstance을 볼 수 있습니다.

이렇게하면 다른 CPU보다 먼저 모든 메모리가 업데이트되도록 하드웨어 차단 명령이 필요합니다. 해당 시스템에서 볼 수 있습니다.

+0

섹션 5의 마지막 부분에서 언급했기 때문에 실제로 그렇게 보이지는 않습니다. 다중 프로세서 실행은 더 많은 문제를 일으킬 수 있습니다.이 외에도 섹션 6은 멀티 프로세서 시스템에서 _DCLP로 명시 적으로 명명됩니다. _ 및 _Inroduction_ 섹션에서 다음을 읽을 수 있습니다. "이 기사에서는 Singleton이 스레드 안전하지 않은 이유와 DCLP가이 문제를 해결하는 방법, DCLP는 단일 및 다중 프로세서 ** 아키텍처 모두에서 실패 할 수 있으며 그 이유는 무엇입니까? "라고 말합니다. – undermind

1

노래를 가리키는 포인터 leton은 휘발성 일 수 있지만 내에서은 그렇지 않습니다.

싱글 톤의 구성원이 int x, y, z;이고 상속자가 15, 16, 17 인 경우를 상상해보십시오. OK

volatile Singleton* volatile temp = new Singleton; 
    pInstance = temp; 

, temppInstance 전에 작성되었습니다. 언제 그들과 관련하여 x,y,z 서면? 전에? 후? 당신은 몰라요. 그것들은 휘발성이 아니므로 휘발성 순서와 관련하여 주문할 필요가 없습니다.

이제 스레드에 와서보고 :

if (pInstance == 0) { // first check 

를 그리고 이제 pInstance 설정 한 가정 해 봅시다, 널 (null)이 아닙니다. x,y,z의 값은 무엇입니까? new Singleton이 호출되었고 생성자가 "실행"한 경우 x,y,z을 설정 한 작업이 실행되었는지 여부를 알 수 없습니다.

그럼 코드는 x,y,z이되고 무작위 데이터가 아닌 15,16,17이 실제로 예상 되었기 때문에 충돌합니다.

오 기다림, pInstance은 휘발성 데이터에 대한 휘발성 포인터입니다! 그래서 x,y,z은 휘발성이 아닙니까? 권리? 따라서 pInstancetemp으로 주문하십시오. 아하!

거의. *pInstance의 모든 읽기는 휘발성이되지만 new Singleton을 통한 구성은 휘발성이 아닙니다. 따라서 x,y,z에 대한 초기 기록은 주문되지 않았습니다. :-(

그래서 당신은 , 어쩌면, 회원에게 volatile int x, y, z; 확인을 만들 수 있습니다. 그러나 ...

C++ 지금 를 메모리 모델을 한 기사가 있었다 때하지 않은 경우에도 작성. 현재의 규칙에 따라, volatile 데이터 인종을 방지하지 않습니다. volatile 스레드와는 아무 상관이있다.이 프로그램은 UB이다. 개와 고양이가 함께 살고. 또한

을,이 표준의 한계를 밀고 있지만 (예 : 무슨 012에 관해서 막연하게된다.은 실제로 모든 것을 아는 완전한 프로그램 최적화 컴파일러로 volatile의 용도를 볼 수 있으며 "해당 휘발성 물질이 실제로 IO 메모리 주소 등에 연결되지는 않는다" 관찰 할 수있는 행동, 나는 단지 그들을 비 휘발성으로 만들 예정이다. "...

+0

죄송합니다. 사실 내가 언급 한 기사의 일부가 생략되었습니다. 질문에 (나는 그것을 명확하게 질문을 만들 것이라고 믿었습니다.) 그 부분에서 저자는 당신이 설명하는 문제를 해결합니다. 생성자의 싱글 톤 필드의 초기화는 'static_cast (x) = 5;'그러나이 작성자는 여전히 그런 해결책이 thread-unsafe 코드의 생성 문제를 해결하지 못한다고 주장한다. 저는 현대 C++가 정교한 메모리 모델을 가지고 있다는 것을 알고 있습니다. 그러나 저자가 의미하는 것은 흥미 롭습니다. – undermind

+0

좋아요, 이제 (다시) 기사를 읽었습니다 (몇 년이 지났음). 나는 당신이 인용하고있는 비트와 다음 섹션으로 이어지는 섹션의 끝은 실제로 많은 무게가 없다고 말하고 싶은 유혹을 받는다. (예를 들어, 캐시 일관성은 일반적으로 멀티 프로세서에서 문제가되지 않습니다 (모든 공통 아키텍처가 캐시 일관성을 보장하므로) 문제는 읽기/쓰기 버퍼와 관련이 있습니다. 아마도 완벽 할 필요는 없습니다.) 아무리해도 휘발성 + 유니 프로세서가 실제로 스레드로부터 안전 할 수 있습니다. 그러나 '휘발성'은 정의가 잘되어 있지 않으므로 믿지 않을 것입니다. – tony

관련 문제