C ++ 프로그래밍 동시 : C ++ 11 원자 연산 및 메모리 모델

C ++ 프로그래밍 동시 : C ++ 11 원자 연산 및 메모리 모델

첫째, 필요 알고

도 1은, 프로그램의 최종 출력에 영향을 미치는 요인은 다음과 아르

  • (넌센스입니다 ...) 코드 작성 순서

    여기가 아님 정교 : 샘플 C ++ 코드가이 주어진다 :

    #include <thread>
    #include <atomic>
    #include <iostream>
    using namespace std;
    atomic<int> a {0};
    atomic<int> b {0};
    int ValueSet(int) {
    	int t = 1;
    	a = t;
    	b = 2;
    }
    int Observer(int) {
    	cout << "(" << a << ", " << b << ")" << endl; // 可能有多种输出
    }
    int main() {
    	thread t1(ValueSet, 0);
    	thread t2(Observer, 0);
    	t1.join();
    	t2.join();
    	cout << "Got (" << a << ", " << b << ")" << endl; // Got (1, 2)
    }
    

    받는 사람이 goes'll 말, 당신은 코드 시퀀스는 반드시 마지막 실행 결과없는 볼 ...

  • 플랫폼 CPU의 기계 명령어의 강도의 메모리 모델 실행 순서

    • 메모리 모델
      메모리 모델은 하드웨어 개념 보통 기계 지침 (또는 독자 그것은 어셈블리 언어 지침도 될 수있는)를 프로세서에 의해 실행 주문할 무엇을 나타냅니다.
    • (예 86)를 강한 메모리 모델 : CPU 실행을위한 컴퓨터 명령어를 순차적으로 생성
    • (파워 등)을 약한 메모리 모델 : CPU 머신 생성 지시 (순서에서) 순서에 따라 수행 할 수있다
    • 참고 : 왜 약한 순차 메모리 모델이있다?
      간단히 순차 약한 메모리 모델, 상기 프로세서는 상기 명령어 병렬 같은 고성능 실행을 탐구 할 수 있도록.
    • (기계 명령들은 대략 여기 볼) 생성 된 의사 어셈블리 코드 위에 다음 샘플 코드 "; A = t; B = 2 t = 1"
    	1: Loadi reg3, 1; 			# 将立即数1放入寄存器reg3
    	2: Move reg4, reg3; 		# 将reg3的数据放入reg4
    	3: Store reg4, a; 			# 将寄存器reg4中的数据存入内存地址a
    	4: Loadi reg5, 2; 			# 将立即数2放入寄存器reg5
    	5: Store reg5, b; 			# 将寄存器reg5中的数据存入内存地址b
    

    CPU 강한 메모리 모델의 실행 순서는 다음과 항상 1-> 2-> 3-> 4 -> (5)
    을 순차적으로 수행 CPU 약한 메모리 모델이다 : 명령 이후 1-> 2-> 3-> 4 -> 5 일 수있다 1, 2, 3, 어떤 조작 지시 4,5- 영향 순서 (다른 레지스터들과 다른 메모리 주소를 사용)가 될 수있다 1-> 3-> 2-> 5-> 3

  • 컴파일러 컴파일러 최적화

    • 약한 메모리 모델을 재정렬에 대한 지침 (어셈블러 지침으로 약 여기) 최종 메모리 모델 컴파일러 생성 기계 명령어의 강도에서 실행되는 컴파일러 의지 코드는 지침 플러스 메모리 장벽의 특정 실행 순서를 필요로한다.
    • 명령 생성 수단 어셈블러 강한 메모리 모델
      A 및 B는 원자 때문에 실행 순서 강한 메모리 모델 CPU 1-> 2-> 3-> 4되므로 항상 변수 디폴트는 AB 최적화 연관된 명령들을 재정렬 컴파일러를 방지하기 위해, 즉 순차적 일관성 원리를 취한다 -> 5
    	1: Loadi reg3, 1; 			# 将立即数1放入寄存器reg3
    	2: Move reg4, reg3; 		# 将reg3的数据放入reg4
    	3: Store reg4, a; 			# 将寄存器reg4中的数据存入内存地址a
    	4: Loadi reg5, 2; 			# 将立即数2放入寄存器reg5
    	5: Store reg5, b; 			# 将寄存器reg5中的数据存入内存地址b
    
    • 약한 메모리 모델 생성 조립체 지시
      A와 B는 원자이기 때문에 변수의 기본값은 AB 어셈블러 코드가 너무 강해 생성 최적화 된 일관성 메모리 모델 생성 관련 지침을 재정렬 컴파일러를 금지 순차적 일관성 원칙을 가지고하는 것입니다,하지만 약한 메모리 모델은 CPU이기 때문에 주문 이행, 또한 추가 메모리 컴파일러 울타리 강제 명령 실행 순서를 필요
      1-> 2-> 3-> 4 -> 5.
      동기화 : 명령 프로세서 전에 완료되면이 명령은 파이프 라인에 강제 된 동기화 명령 실행 후 (파이프 라인을 비우는). 그 결과, 동기화하기 전에 지침을 운영하는 것은 항상 동기화가 완료 후 명령 앞에옵니다.
    	1: Loadi reg3, 1; 			# 将立即数1放入寄存器reg3
    	2: Move reg4, reg3; 		# 将reg3的数据放入reg4
    	3: Store reg4, a; 			# 将寄存器reg4中的数据存入内存地址a
    	4: Sync 					# 内存栅栏
    	5: Loadi reg5, 2; 			# 将立即数2放入寄存器reg5
    	6: Store reg5, b; 			# 将寄存器reg5中的数据存入内存地址b
    

두, C ++ 11 메모리 모델

도 1에서, 메모리 모델 열거

열거 값 정의 된 규칙
memory_order_relaxed 그것은 어떤 보증 실행 순서가되지 않습니다
memory_order_acquire 이 스레드는 모든 후속하는 판독 동작은 조작부 원자의 완료 후에 수행해야
memory_order_release 쓰기 작업이 완료되기 전에이 스레드는이 섹션의 모든 후 원자 작업을 수행 할 수 있습니다
memory_order_acq_rel 그리고 memory_order_release 태그 memory_order_acquire을 포함
memory_order_consume 원 동작의 유형에 대한 모든 후속 스레드는 본 조작부 원자의 완료 후에 수행해야
memory_order_seq_cst 모든 액세스는 순서대로 실행됩니다

2 분류 간단한 메모리 모델

  • , memory_order_seq_cst을 memory_order_release memorey_order_relaxed을 사용할 수있다 : 원자 동작 (저장소)에 저장된다.

  • memory_order_consume, memory_order_acquire, memory_order_seq_cst, memorey_order_relaxed 사용할 수 있습니다 : 원자 작동 (부하)을 참조하십시오.

  • RMW 동작 (읽기 - 수정 - 쓰기) 즉, 이러한 언급 이전 atomic_flag 형 test_and_set () 동작과 동시 읽기 및 쓰기 동작을 요구한다. 다른 실시 atomic_compare_exchange 원자 클래스 템플릿 () 동작을 동시에 판독 및 기록하여야한다. RMW 작업 memory_order_consume이 memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst, memorey_order_relaxed 사용할 수 있습니다.

  • 형태 "연산자 ="일부 "는 연산자 + ="기능은, 실제로, 단순히 파라미터로서 동작 memory_order_seq_cst memory_order 원자를 포장한다.

3, C ++ 11 메모리 모델은 일반적으로 사용

  • 같은 순서 유형에서
    데이터 메모리 원자 서열 유형 memory_order_seq_cst 그 때문에 성능 실을 플레이하기 쉬운 시스템을 방해하고, 너무 높으면
	#include <thread>
	#include <atomic>
	#include <iostream>
	using namespace std;
	atomic<int> a;
	atomic<int> b;
	int Thread1(int) {
		int t = 1;
		a.store(t, memory_order_seq_cst);
		b.store(2, memory_order_seq_cst);
	}
	int Thread2(int) {
		while(b.load(memory_order_seq_cst) != 2); // 自旋等待
		cout << a.load(memory_order_seq_cst) << endl;
	}
	int main() {
		thread t1(Thread1, 0);
		thread t2(Thread2, 0);
		t1.join();
		t2.join();
		return 0;
	}
  • 느슨하게
    memorey_order_relaxed 주문 번호 메모리 요구 사항, 프로그램은 작업의 결과를 보장 할 수 없습니다
	#include <thread>
	#include <atomic>
	#include <iostream>
	using namespace std;
	atomic<int> a;
	atomic<int> b;
	int Thread1(int) {
		int t = 1;
		a.store(t, memory_order_relaxed);
		b.store(2, memory_order_relaxed);
	}
	int Thread2(int) {
		while(b.load(memory_order_relaxed) != 2); // 自旋等待
		cout << a.load(memory_order_relaxed) << endl;
	}
	int main() {
		thread t1(Thread1, 0);
		thread t2(Thread2, 0);
		t1.join();
		t2.join();
		return 0;
	}
  • 릴리스 취득 型
    b.store 전에 a.store 발생
    출현 a.laod 이전 b.load
    완전히 코드의 정확성을 보장 실행, 즉 B (2)의 값이 1의 값도 결정되는 시간. 인쇄 문은 스핀 대기의 값 앞에 인쇄되지 않습니다
	#include <thread>
	#include <atomic>
	#include <iostream>
	using namespace std;
	atomic<int> a;
	atomic<int> b;
	int Thread1(int) {
	int t = 1;
		a.store(t, memory_order_relaxed);
		b.store(2, memory_order_release); // 本原子操作前所有的写原子操作必须完成
	}
	int Thread2(int) {
		while(b.load(memory_order_acquire) != 2); // 本原子操作必须完成才能执行之后所有的读原子操作
		cout << a.load(memory_order_relaxed) << endl; // 1
	}
	int main() {
		thread t1(Thread1, 0);
		thread t2(Thread2, 0);
		t1.join();
		t2.join();
		return 0;
	}
  • 해제 - 소비 型
    이러한 메모리 주문 보장 ptr.load (memory_order_consume)이 발생해야 이러한 작업 솔루션 전에 * PTR 참조
    하지 data.load 전에 발생하지 보증 (memory_order_relaxed)
	#include <thread>
	#include <atomic>
	#include <cassert>
	#include <string>
	using namespace std;
	atomic<string*> ptr;
	atomic<int> data;
	void Producer() {
		string* p = new string("Hello");
		data.store(42, memory_order_relaxed);
		ptr.store(p, memory_order_release);
	}
	void Consumer() {
		string* p2;
		while (!(p2 = ptr.load(memory_order_consume)))
			;
		assert(*p2 == "Hello"); // 总是相等
		assert(data.load(memory_order_relaxed) == 42); // 可能断言失败
	}
	int main() {
		thread t1(Producer);
		thread t2(Consumer);
		t1.join();
		t2.join();
	}
  • 취득 출시 型
    다른 예 memory_order_acq_rel은 일반적으로 (비교 및 교환) CAS 불리는 기본적인 동기 프리미티브에 사용되는 원자 원자 compare_exchange_strong 체 기능의 동작에 대응한다.
게시 된 155 개 원래 기사 · 원의 찬양 (15) · 전망 160 000 +

추천

출처blog.csdn.net/wangdamingll/article/details/104446740