프로그래밍 언어/C++

C ++ 11은 표준화 된 메모리 모델의 도입이 미치는 영향

Rateye 2021. 7. 28. 10:30
728x90
반응형
질문 : C ++ 11은 표준화 된 메모리 모델을 도입했습니다. 무슨 뜻이에요? 그리고 그것이 C ++ 프로그래밍에 어떤 영향을 미칠까요?

C ++ 11은 표준화 된 메모리 모델을 도입했지만 정확히 무엇을 의미합니까? 그리고 그것이 C ++ 프로그래밍에 어떤 영향을 미칠까요?

이 기사 ( Herb Sutter 를 인용 한 Gavin Clarke의 )는 다음과 같이 말합니다.

메모리 모델은 C ++ 코드가 이제 컴파일러를 만든 사람과 실행중인 플랫폼에 관계없이 호출 할 표준화 된 라이브러리를 가지고 있음을 의미합니다. 서로 다른 스레드가 프로세서의 메모리와 통신하는 방식을 제어하는 표준 방법이 있습니다.

Sutter 는 "표준에있는 여러 코어로 [코드]를 분할하는 것에 대해 이야기 할 때 메모리 모델에 대해 이야기하고 있습니다. 우리는 사람들이 코드에서 할 다음 가정을 깨지 않고 최적화 할 것입니다."라고 Sutter는 말했습니다.

글쎄, 나는 온라인에서 사용할 수있는이 단락과 유사한 단락을 외울 수있다 (내가 태어날 때부터 내 자신의 기억 모델을 가지고 있었기 때문에 : P) 다른 사람들이 묻는 질문에 대한 답변으로 게시 할 수도 있지만, 솔직히 정확히 이해하지 못한다 이.

C ++ 프로그래머는 이전에도 멀티 스레드 애플리케이션을 개발하는 데 사용되었는데 POSIX 스레드 든 Windows 스레드 든 C ++ 11 스레드 든 상관 없습니다. 이점은 무엇입니까? 낮은 수준의 세부 사항을 이해하고 싶습니다.

나는 또한 C ++ 11 메모리 모델이 C ++ 11 멀티 스레딩 지원과 관련이 있다는 느낌을받습니다. 그렇다면 정확히 어떻게? 왜 연관되어야합니까?

멀티 스레딩의 내부가 어떻게 작동하는지, 일반적으로 메모리 모델이 무엇을 의미하는지 모르기 때문에 이러한 개념을 이해하도록 도와주세요. :-)

반응형
답변

첫째, 언어 변호사처럼 생각하는 법을 배워야합니다.

C ++ 사양은 특정 컴파일러, 운영 체제 또는 CPU를 참조하지 않습니다. 실제 시스템의 일반화 인 추상 기계 를 참조합니다. 언어 변호사 세계에서 프로그래머의 임무는 추상 기계를위한 코드를 작성하는 것입니다. 컴파일러의 역할은 구체적인 기계에서 해당 코드를 구현하는 것입니다. 사양에 따라 엄격하게 코딩하면 현재 또는 지금부터 50 년 후 호환되는 C ++ 컴파일러가있는 시스템에서 수정없이 코드가 컴파일되고 실행된다는 것을 확신 할 수 있습니다.

C ++ 98 / C ++ 03 사양의 추상 시스템은 기본적으로 단일 스레드입니다. 따라서 사양과 관련하여 "완전히 이식 가능한"다중 스레드 C ++ 코드를 작성할 수 없습니다. 사양은 메모리로드 및 저장 의 원 자성 또는로드 및 저장이 발생할 수있는 순서 에 대해서는 언급하지 않으며 뮤텍스와 같은 것은 신경 쓰지 마십시오.

물론, pthreads 또는 Windows와 같은 특정 구체적인 시스템을 위해 실제로 다중 스레드 코드를 작성할 수 있습니다. 그러나 C ++ 98 / C ++ 03에 대한 다중 스레드 코드를 작성하는 표준 방법은 없습니다.

C ++ 11의 추상 기계는 설계 상 다중 스레드입니다. 또한 잘 정의 된 메모리 모델이 있습니다 . 즉, 컴파일러가 메모리에 액세스 할 때 수행 할 수있는 작업과 수행하지 않을 수있는 작업을 말합니다.

두 개의 스레드가 동시에 한 쌍의 전역 변수에 액세스하는 다음 예제를 고려하십시오.

           Global
           int x, y;

Thread 1            Thread 2
x = 17;             cout << y << " ";
y = 37;             cout << x << endl;

Thread 2는 무엇을 출력 할 수 있습니까?

C ++ 98 / C ++ 03에서는 정의되지 않은 동작도 아닙니다. 표준이 "스레드"라고하는 것을 고려하지 않기 때문에 질문 자체는 의미가 없습니다.

C ++ 11에서는로드 및 저장이 일반적으로 원자적일 필요가 없기 때문에 결과는 정의되지 않은 동작입니다. 그다지 개선 된 것 같지 않을 수도 있습니다 ... 그리고 그 자체로는 그렇지 않습니다.

그러나 C ++ 11에서는 다음과 같이 작성할 수 있습니다.

           Global
           atomic<int> x, y;

Thread 1                 Thread 2
x.store(17);             cout << y.load() << " ";
y.store(37);             cout << x.load() << endl;

이제 상황이 훨씬 더 흥미로워집니다. 우선 여기에서 동작이 정의됩니다 . 스레드 2는 이제 0 0 (스레드 1 이전에 실행되는 경우), 37 17 (스레드 1 이후에 실행되는 경우) 또는 0 17 (스레드 1이 x에 할당 된 후에 실행되지만 y에 할당되기 전에 실행되는 경우)를 인쇄 할 수 있습니다.

C ++ 11의 원자로드 / 저장에 대한 기본 모드는 순차 일관성 을 적용하는 것이기 때문에 인쇄 할 수없는 것은 37 0 입니다. 이는 모든로드와 저장이 각 스레드 내에서 작성한 순서대로 발생하는 것처럼 "마치"있어야한다는 의미이며, 스레드 간의 작업은 시스템이 원하는대로 인터리브 될 수 있습니다. 따라서 atomics의 기본 동작은로드 및 저장에 대한 원자 성과 순서를 모두 제공합니다.

이제 최신 CPU에서는 순차 일관성을 보장하는 데 많은 비용이들 수 있습니다. 특히 컴파일러는 여기에서 모든 액세스 사이에 완전한 메모리 장벽을 내 보냅니다. 그러나 알고리즘이 비 순차적로드 및 저장을 허용 할 수 있다면; 즉, 원 자성이 필요하지만 순서는 필요하지 않은 경우; 37 0 을 허용 할 수 있다면 다음과 같이 작성할 수 있습니다.

           Global
           atomic<int> x, y;

Thread 1                            Thread 2
x.store(17,memory_order_relaxed);   cout << y.load(memory_order_relaxed) << " ";
y.store(37,memory_order_relaxed);   cout << x.load(memory_order_relaxed) << endl;

최신 CPU 일수록 이전 예보다 더 빠를 가능성이 높습니다.

마지막으로, 특정로드 및 스토어를 순서대로 유지해야하는 경우 다음과 같이 작성할 수 있습니다.

           Global
           atomic<int> x, y;

Thread 1                            Thread 2
x.store(17,memory_order_release);   cout << y.load(memory_order_acquire) << " ";
y.store(37,memory_order_release);   cout << x.load(memory_order_acquire) << endl;

이렇게하면 순서가 지정된로드 및 저장으로 돌아갑니다. 따라서 37 0 은 더 이상 가능한 출력이 아니지만 최소한의 오버 헤드로 수행됩니다. (이 사소한 예에서 결과는 완전한 순차 일관성과 동일하며 더 큰 프로그램에서는 그렇지 않습니다.)

물론,보고 싶은 유일한 출력이 0 0 또는 37 17 이면 원래 코드를 뮤텍스로 감쌀 수 있습니다. 그러나 당신이 여기까지 읽었다면, 나는 그것이 어떻게 작동하는지 이미 알고 있다고 확신하며,이 대답은 이미 내가 의도 한 것보다 깁니다 :-).

그래서, 결론. 뮤텍스는 훌륭하며 C ++ 11은이를 표준화합니다. 그러나 때로는 성능상의 이유로 더 낮은 수준의 프리미티브 (예 : 고전적인 이중 검사 잠금 패턴 )를 원합니다. 새로운 표준은 뮤텍스 및 조건 변수와 같은 고수준 가젯을 제공하며 원자 유형 및 다양한 메모리 장벽과 같은 저수준 가젯도 제공합니다. 따라서 이제 표준에 지정된 언어 내에서 정교한 고성능 동시 루틴을 작성할 수 있으며 코드가 현재 시스템과 미래 시스템 모두에서 변경되지 않고 컴파일되고 실행될 것임을 확신 할 수 있습니다.

솔직히 말해서 전문가가 아니고 심각한 저수준 코드를 작업하지 않는 한 뮤텍스와 조건 변수를 고수해야합니다. 그게 제가하려는 일입니다.

이에 대한 자세한 내용은 이 블로그 게시물을 참조하십시오.

출처 : https://stackoverflow.com/questions/6319146/c11-introduced-a-standardized-memory-model-what-does-it-mean-and-how-is-it-g
728x90
반응형