c++병렬 프로 그래 밍(5)-원자 유형 과 원자 조작 atomic

원자 조작 은 분리 할 수 없 는 조작 으로 표준 c++에서 원자 유형 을 통 해 원자 조작 을 얻 을 수 있다.
간단 한 예 를 들 어 원자 유형 을 사용 하 는 역할 을 살 펴 보 자.
std::atomic sum = 0; 
//int sum = 0;

void fun()
{
	for (int i = 0; i<100000; ++i)
		sum ++;                   //       sum       
}

int main()
{
	std::cout << "Before joining,sun = " << sum << std::endl;
	std::thread t1(fun);
	std::thread t2(fun);
	t1.join();
	t2.join();
	std::cout << "After joining,sun = " << sum << std::endl;
	system("pause");
	return 0;
}

원자 형식 을 사용 하면 잠 금 이 없 는 스 레 드 간 데이터 공 유 를 완성 할 수 있 습 니 다.
가장 간단 한 표준 원자 유형 std::atomic플래그
//  std::atomic_flag        
class spinlock_mutex {
	std::atomic_flag flag = ATOMIC_FLAG_INIT;
public:
	spinlock_mutex() {}
	
	void lock() {
		while (flag.test_and_set(std::memory_order_acquire));
	}

	void unlock() {
		flag.clear(std::memory_order_release);
	}
};

eg:c+표준 은 자전 자 물 쇠 를 제공 하지 않 습 니 다.자 회전 자 물 쇠 는 다 중 스 레 드 공유 자원 을 보호 하 는 자물쇠 입 니 다.일반적인 상호 배척 자물쇠(mutex)와 다른 점 은 자 회전 자물쇠 가 자물쇠 의 소유권 을 가 져 오 려 고 할 때 바 쁜 대기(busy waiting)형식 으로 자물쇠 가 사용 가능 한 지 계속 순환 검사 하 는 것 입 니 다.다 중 프로세서 환경 에서 잠 금 시간 이 비교적 짧 은 프로그램 에 대해 서 는 일반적인 상호 배척 잠 금 대신 자전 자 물 쇠 를 사용 하면 프로그램의 성능 을 향상 시 킬 수 있다.
그 중에서 회색 사각형 의 3 단 계 는 분리 할 수 없 는 원자 조작 이 어야 한다.자전 자 물 쇠 를 풀 때 원자 조작 형식 으로 flag 를 false 로 설정 하면 됩 니 다.
std::atomic_flag 대상 은 두 가지 조작 만 포함 합 니 다-testand_set()&clear()-그리고 모두 원자 조작 입 니 다.
test_and_set()는 읽 기-수정-쓰기 동작 입 니 다.flag 가 false 일 때 성공 하면 true 로 돌아 갑 니 다.
clear()는 저장 작업 으로 flag 를 false 로 설정 합 니 다.
std::atomic
기본 유형(예 를 들 어 int,double*등)에 std::atomic 템 플 릿 을 원자 유형 으로 포장 하고 사용 할 수 있 는 원자 조작 은 load,store,exchange,compare 등 이 있 습 니 다.
원자 조작의 메모리 순서
프로그램 코드 를 최적화 하기 위해 컴 파 일 러 와 프로 세 서 는 상호 의존 관계 가 없 는 모든 명령 을 자 유 롭 게 다시 배열 할 수 있다.예 를 들 어 두 개의 분배 문 a=0;B=1;,그것들 은 어떤 순서 로 든 집행 할 수 있다.그러나 다 중 스 레 드 환경 에서 서로 다른 스 레 드 메모리 작업 간 의 의존성 은 컴 파일 러 나 프로세서 에 보이 지 않 기 때문에 컴 파일 러 나 프로세서 에 명령 을 실행 하고 정렬 하 는 데 오류 가 발생 할 수 있 습 니 다.원자 작업 의 메모리 순 서 를 제정 하여 스 레 드 간 원자 문맥 동기 화 결합 성 을 약화 시 켜 실행 효율 을 높 인 다.
기본 std::memory 대신 메모리 순 서 를 지정 합 니 다.order_seq_cst 는 성능 을 향상 시 킬 수 있다.C++11 의 std::memoryorder 는 여섯 개의 매 거 진 값 이 있 습 니 다.
Value
묘사 하 다.
std::memory_order_relaxed
동기 화 와 정렬 제한 이 없 으 며,조작 이 원자 라 는 것 만 보증 해 야 한다.
std::memory_order_consume
이 값 을 지정 한 load 작업 은 영향 을 받 는 메모리 위치 에서 consume 작업 을 수행 합 니 다.이 작업 은 같은 메모리 위치 에서 release 작업 을 수행 한 다른 스 레 드 가 그 전에 데이터 의존(data-dependent)메모리 위치 에 대한 쓰기 동작 을 현재 스 레 드 로 볼 수 있 습 니 다.
 
std::memory_order_acquire
이 값 을 지정 한 load 작업 은 영향 을 받 은 메모리 위치 에서 acquire 작업 을 수행 합 니 다.이 작업 은 같은 메모리 위치 에서 release 작업 을 수행 한 다른 스 레 드 를 현재 스 레 드 로 볼 수 있 습 니 다.
std::memory_order_release
이 값 을 지정 한 store 작업 은 영향 을 받 는 메모리 위치 에서 release 작업 을 수행 합 니 다.이 작업 은 이 스 레 드 전에 데이터 의존(data-dependent)의 메모리 위치 에 대한 쓰기 체 조 를 다른 메모리 위치 로 한 다음 에 같은 메모리 위치 에서 consume 작업 을 수행 하 는 라인 을 통 해 볼 수 있 습 니 다.이 스 레 드 전에 임의의 메모리 위치 에 대한 쓰기 체 조 를 다른 스 레 드 로 만 든 다음 같은 메모리 위치 에서 acquire 작업 을 수행 하 는 스 레 드 를 통 해 볼 수 있 습 니 다.
std::memory_order_acq_rel
이 값 을 지정 한 read-modify-write 작업 은 읽 기 단계(load 에 해당 함)에서 영향 을 받 는 메모리 위치 에 acquire 작업 을 수행 하고 쓰기 단계(store 에 해당 함)에서 같은 메모리 위치 에 release 작업 을 수행 합 니 다.
std::memory_order_seq_cst
순서 일치 성,모든 스 레 드 가 관찰 한 전체 프로그램 에서 메모리 수정 순서 가 일치 합 니 다.
 
순서 일치 성 순서 std:memoryorder_seq_cst
온라인 프로 세 스 a 에서\#1 작업 은\#2 전에 순서 일치 성 순 서 를 사용 하고 온라인 프로 세 스 b 에서 도 이 순서 로 간주 합 니 다.즉,순서 가 일치 하면 모든 스 레 드 간 의 전체 동기 화 를 요구한다.
std::atomic data;
std::atomic data_ready(false);

//   a
void writer_thread()
{
	data.store(10,std::memory_order_seq_cst);             // #1: data    
	data_ready.store(true, std::memory_order_seq_cst);     // #2: data_ready    
}

//   b
void reader_thread()
{
	while (!data_ready.load(std::memory_order_seq_cst)) {} // #3: data_ready    
	
	std::cout << "data is "<< data.load(std::memory_order_seq_cst) << "
"; // #4: data } int main() { std::thread a(reader_thread); std::thread b(writer_thread); a.join(); b.join(); system("pause"); }

느슨 한 순서 std::memoryorder_relaxed
이 때 스 레 드 b 에서 조작\#1 과 조작\#2 의 순서 가 정 해 지지 않 습 니 다.아마도 dataready 가 true 일 때 data 는 0 입 니 다.
std::atomic data;
std::atomic data_ready(false);

//   a
void writer_thread()
{
	data.store(10,std::memory_order_relaxed);             // #1: data    
	data_ready.store(true, std::memory_order_relaxed);     // #2: data_ready    
}

//   b
void reader_thread()
{
	while (!data_ready.load(std::memory_order_relaxed)) {} // #3: data_ready    
	
	std::cout << "data is "<< data.load(std::memory_order_relaxed) << "
"; // #4: data } int main() { std::thread b(writer_thread); std::thread a(reader_thread); a.join(); b.join(); system("pause"); }

획득-방출 순서 std::memoryorder_acquire&std::memory_order_release
느슨 한 순서 가 너무 자 유 롭 고 순서 일치 성 순서 가 너무 엄격 하기 때문에 석방 순 서 를 제공 합 니 다.
 
std::atomic data;
std::atomic data_ready(false);

//   a
void writer_thread()
{
	data.store(10,std::memory_order_relaxed);             // #1: data    
	data_ready.store(true, std::memory_order_release);     // #2: data_ready    
}

//   b
void reader_thread()
{
	while (!data_ready.load(std::memory_order_acquire)) {} // #3: data_ready    
	
	std::cout << "data is "<< data.load(std::memory_order_relaxed) << "
"; // #4: data } int main() { std::thread b(writer_thread); std::thread a(reader_thread); a.join(); b.join(); system("pause"); }

std::memory_order_consume
때로는 석방 순서 도 엄격 하 다 고 생각 할 때 가 있 습 니 다.저 는 단지 보증 하고 싶 을 뿐 입 니 다.order_consume
std::atomic data;
std::atomic data_ready(false);

//   a
void writer_thread()
{

	data_ready.store(true, std::memory_order_relaxed);     // #2: data_ready    
	data.store(10, std::memory_order_relaxed);             // #1: data    
}

//   b
void reader_thread()
{
	while (!data_ready.load(std::memory_order_consume)) {} // #3: data_ready    
	
	std::cout << "data is "<< data.load(std::memory_order_relaxed) << "
"; // #4: data } int main() { std::thread b(writer_thread); std::thread a(reader_thread); a.join(); b.join(); system("pause"); }

 
마지막 으로 여기 잘 한 편 이 있 습 니 다.전재 해 주세요.
https://www.zhihu.com/question/24301047/answer/85844428

좋은 웹페이지 즐겨찾기