atomic

#include <atomic>
std::atomic<int> counter(0);

여러 쓰레드에서 atomic 객체 자원을 수정할 때 원자적 연산(CPU가 명령어 한개로 처리하는 명령)을 사용하면 mutex를 사용하지 않아도 정상적인 결과가 나온다.

 

 

memory order

멀티 쓰레드 환경에서 컴파일러와 CPU가 명령어 순서를 재배치하여 환경에 따라 결과가 달라지는 문제를 막기 위해 메모리 재배치 순서를 강제할 수 있다.

 

memory_order_relaxed (자유)

// atomic<int> 객체 포인터 a, b, c에 대해

// memory_order_relaxed
// 스레드 내부에서 두 대입 명령들의 순서는 바뀔 수 있다. (CPU가 마음대로 재배치 가능하다.)
int x = a->load(memory_order_relaxed);  // x = a (읽기, 원자적 연산)
b->store(1, memory_order_relaxed);      // b = 1 (쓰기, 원자적 연산)

c->fetch_add(2, memory_order_relaxed); // c = c + 2 

c->is_lock_free() // c 객체의 연산들이 원자적으로 구현될 수 있는지 확인
// true인 경우 mutex의 lock unlock 없이도 연산을 올바르게 수행할 수 있다는 뜻

 

memory_order_acquire와 memory_order_release

// 두 쓰레드가 공유하는 변수 data의 release와 acquire을 사용하여 동기화를 수행하는 코드

void producer() {
  data[0].store(1, memory_order_relaxed);
  data[1].store(2, memory_order_relaxed);
  data[2].store(3, memory_order_relaxed);
  is_ready.store(true, std::memory_order_release);
}

void consumer() {
  // data 가 준비될 때 까지 기다린다. (스핀 락)
  while (!is_ready.load(std::memory_order_acquire)) {
  }

  std::cout << "data[0] : " << data[0].load(memory_order_relaxed) << std::endl;
  std::cout << "data[1] : " << data[1].load(memory_order_relaxed) << std::endl;
  std::cout << "data[2] : " << data[2].load(memory_order_relaxed) << std::endl;
}

 

memory_order_release는 해당 명령 이전의 모든 메모리 명령(읽기, 쓰기)들이 해당 명령 이후로 재배치 되는 것을 금지한다.

 

memory_order_acquire는 해당 명령 뒤에 오는 모든 메모리 명령들이 해당 명령 위로 재배치 되는 것을 금지한다.

 

memory_order_acq_rel

ㄴ acquire와 release를 모두 수행하는 것

ㄴ 읽기와 쓰기를 모두 수행하는 명령들, 예를 들어 fetch_add와 같은 함수에서 사용될 수 있다.

 

memory_order_seq_cst

ㄴ 메모리 명령의 순차적 일관성을 보장해준다. (모든 쓰레드에서 모든 시점에 동일한 값을 관찰할 수 있게 해준다.)

ㄴ atomic 객체를 사용할 때 memory_order를 지정해주지 않는다면 디폴트로 memory_order_seq_cst가 지정된다.

ㄴ memory_order_seq_cst를 사용하는 메모리 연산들끼리는 모든 쓰레드에서 동일한 연산 순서를 관찰할 수 있도록 보장해준다.

ㄴ 멀티 코어 시스템에서 비싼 연산이다. AMD 계열 CPU는 차이가 크지 않지만 ARM 계열은 동기화 비용이 크다.

 

참조:

https://modoocode.com/271

'C++' 카테고리의 다른 글

C++ r-value 참조와 move, 이동 생성자  (0) 2022.08.25
C++ 문자열 처리  (0) 2022.08.24
C++ thread, mutex, condition_variable  (0) 2022.08.23
C++ STL 컨테이너 정리  (0) 2022.08.22
C++ 언어 환경의 빌드 과정  (0) 2022.07.26

+ Recent posts