일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 네트워크보안
- 보안
- 컴퓨터과학
- I'm Sorry
- 사이버보안
- 딥러닝
- 컴퓨터공학
- 클라우드컴퓨팅
- 인공지능
- 자바스크립트
- Yes
- 자료구조
- 데이터베이스
- 빅데이터
- 코딩
- 2
- 머신러닝
- 네트워크
- 데이터구조
- 데이터과학
- 데이터분석
- 알고리즘
- 컴퓨터비전
- 소프트웨어
- 프로그래밍
- 버전관리
- 프로그래밍언어
- 소프트웨어공학
- 웹개발
- 파이썬
- Today
- Total
스택큐힙리스트
C++11은 표준화된 메모리 모델을 도입했습니다. 이것은 무엇을 의미하며, C++ 프로그래밍에 어떤 영향을 미치게 될까요? 본문
C++11은 표준화된 메모리 모델을 도입했습니다. 이것은 무엇을 의미하며, C++ 프로그래밍에 어떤 영향을 미치게 될까요?
스택큐힙리스트 2023. 3. 24. 17:45C++11은 표준화된 메모리 모델을 도입했지만, 이게 정확히 무엇을 의미하며, C++ 프로그래밍에 어떤 영향을 미칠까요?
This article (Gavin Clarke 인용인 Herb Sutter)는 다음과 같이 말합니다.
메모리 모델은 C++ 코드가 이제 컴파일러를 만든 사람과 플랫폼에 관계없이 호출할 수 있는 표준 라이브러리를 갖게 되었다는 것을 의미합니다. 서로 다른 스레드가 프로세서의 메모리와 대화하는 방식을 제어하는 표준 방법이 있습니다.
여러 코어 간에 [코드]를 나누는 것에 대해 이야기할 때, 우리는 표준에서 메모리 모델에 대해 이야기하고 있습니다. 우리는 코드에서 사람들이 하는 가정을 깨뜨리지 않으면서 최적화할 것입니다, Sutter가 말했습니다.
음, 저는 인터넷에서 이와 비슷한 단락들을 기억할 수 있을 뿐만 아니라 (그래서 생일부터 기억 모델을 가지고 있으니까 :P) 다른 질문에 대한 답변으로 게시할 수도 있지만, 솔직히 말해서 이해를 정확히 하고 있지는 않습니다.
C++ 프로그래머들은 이전에도 멀티 스레드 응용 프로그램을 개발했었으므로 POSIX 스레드, Windows 스레드 또는 C++ 11 스레드가 없어도 상관이 없을까요? 이것들의 이점은 무엇인가요? 저는 낮은 수준의 세부 정보를 이해하고 싶습니다.
나 또한 C++11 메모리 모델이 C++11 멀티 스레딩 지원과 어떤 관련이 있는 것 같은 느낌을 받습니다. 자주 함께 보이기 때문입니다. 이것이 맞다면, 정확히는 어떻게 관련이 있는 것인가요? 그들이 관련이 있어야 하는 이유는 무엇인가요?
나는 멀티 스레딩의 내부 구조가 어떻게 작동하는지, 그리고 일반적으로 메모리 모델이 무엇을 의미하는지 모르겠습니다.
답변 1
먼저, 언어 변호사처럼 생각하는 법을 배워야 합니다.
C++ 명세서는 특정 컴파일러, 운영 체제 또는 CPU에 대한 언급이 없습니다. 대신 이는 실제 시스템의 추상화 된 기계에 대한 참조입니다. Language Lawyer의 세계에서 프로그래머의 역할은 추상화 된 기계에 대한 코드를 작성하는 것이며, 컴파일러의 역할은 이를 구체적인 기계에서 실현시키는 것입니다. 명세서에 엄격하게 코딩함으로써, 여러분의 코드가 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;
2번 스레드가 무엇을 출력할 수 있나요?
C++98/C++03에서는 심지어 정의되지 않은 동작도 아닙니다. 표준에서 쓰레드라는 것을 고려하지 않기 때문에 이 질문 자체가 의미가 없습니다.
C++11에서는 일반적으로 로드와 스토어가 원자적이지 않아 결과가 정의되지 않은 동작입니다. 이것은 개선된 것처럼 보이지 않을 수 있습니다. 그 자체로는 그렇지 않습니다.
하지만 C++11로 다음과 같이 작성할 수 있습니다.
Global
atomic
Thread 1 Thread 2
x.store(17); cout << y.load() << ;
y.store(37); cout << x.load() << endl;
이제 일이 훨씬 더 재미있어집니다. 우선, 여기서의 동작은 정의되어 있습니다. 스레드 2는 이제 Thread 1보다 먼저 실행된다면 0 0를 출력 할 수 있고, 그렇지 않으면 Thread 1이 실행된 후에 37 17를 출력 할 수 있으며, 스레드 1이 x에 할당한 후 y에 할당하기 전에 실행된다면 0 17를 출력 할 수 있습니다.
C++11에서 원자 형태의 로드/스토어의 기본 모드는 순차 일관성을 적용하기 때문에 37 0와 같은 것을 인쇄할 수 없습니다. 이는 모든 로드 및 저장 작업은 각 스레드 내에서 작성된 순서대로 as if 발생한 것처럼 처리되어야 함을 의미하며, 스레드 간 작업은 시스템이 원하는 대로 교차될 수 있습니다. 따라서 원자의 기본 동작은 로드 및 저장에 대해 원자성과 순서 지정을 모두 제공합니다.
지금은 현대 CPU에서 일련의 일관성을 보장하는 것이 비용이 많이 들 수 있습니다. 특히, 컴파일러는 여기에서 모든 액세스 사이에 완전한 메모리 배리어를 발행할 가능성이 높습니다. 그러나 알고리즘이 순서를 유지하지 않는 로드 및 저장을 용인할 수 있는 경우, 즉 원자성은 필요하지만 순서는 필요하지 않는 경우 즉,이 프로그램의 출력으로 37 0을 용인할 수 있는 경우, 다음과 같이 작성할 수 있습니다.
Global
atomic
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
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은 이것을 표준화합니다. 그러나 때로는 성능 상의 이유로 하위 수준 기본 요소를 원합니다 (예: 클래식 double-checked locking pattern). 새로운 표준은 뮤텍스 및 조건 변수와 같은 고급 가젯뿐만 아니라 원자 유형과 메모리 벽의 다양한 플레이버와 같은 저수준 가젯을 제공합니다. 이제 표준으로 지정된 언어 내에서 세련되고 고성능의 동시 루틴을 완전히 작성할 수 있으며, 코드가 현재 시스템과 내일의 시스템에서 변경 없이 컴파일 및 실행됨을 확신할 수 있습니다.
솔직히 말해서, 심각한 저수준 코드를 다루는 전문가가 아니라면, 확실히 뮤텍스와 조건 변수에만 집중하는 것이 좋을 겁니다. 그게 제 계획입니다.
이에 대한 자세한 내용은 this blog post 를 참조하세요.
답변 2
C++11에서는 표준화된 메모리 모델이 도입되었습니다. 이것이 무엇을 의미하는지와 C++ 프로그래밍에 어떤 영향을 미칠 것인지 살펴보겠습니다.메모리 모델이란, 프로그램에서 여러 개의 스레드가 동시에 메모리 접근을 하면서 데이터 일관성 문제가 발생하는 것을 방지하기 위한 규칙적인 메모리 액세스 규칙을 의미합니다. 이 규칙을 통해 스레드 간의 경쟁 상황을 조절하고, 데이터 일관성을 유지할 수 있습니다.
기존의 C++에서는 이러한 메모리 모델이 없어서, 메모리 접근 시 발생하는 경쟁 상황이나 일관성 문제를 해결하기 위해서는 별도의 라이브러리나 패턴을 사용해야 했습니다. 하지만 C++11에서부터는 이를 위한 표준화된 방법이 도입됩니다.
C++11에서는 내부적으로 스레드간의 메모리 액세스 규칙을 명확하게 정의합니다. 이를 통해 개발자는 명시적으로 스레드 간의 경쟁 상황을 조절하고, 데이터 일관성을 유지하는 코드를 작성할 수 있습니다. 이를 위해 C++11에서는 std::atomic이라는 새로운 키워드를 제공하며, 이를 통해 안전하게 공유 자원에 접근할 수 있습니다.
또한 C++11에서는 멀티코어 CPU의 성능을 최대한 활용하기 위한 새로운 동시성 라이브러리가 추가되었습니다. 이 라이브러리는 스레드 관리, 동기화, 락 등을 쉽게 구현할 수 있도록 도와주며, 멀티코어 CPU를 활용한 병렬 처리를 용이하게 합니다.
이러한 변경 사항들이 C++ 프로그래밍에 어떤 영향을 미칠까요? 우선, 멀티코어 CPU 시대에 맞게 C++11에서 제공하는 새로운 기능을 적극 활용해서 성능을 최적화하는 것이 중요합니다. 또한, 스레드 관리와 동기화 등을 더 쉽게 구현할 수 있기 때문에, 복잡한 병렬 처리 코드를 작성하는 것이 더욱 쉬워졌습니다.
전반적으로 C++11의 표준화된 메모리 모델과 동시성 라이브러리는 C++ 프로그래밍을 더욱 안전하고 효율적으로 만들어줍니다. 이를 잘 활용하면 더욱 좋은 프로그래밍 경험을 할 수 있을 것입니다.