C++

메모리 모델

춤추는수달 2022. 2. 1. 01:18
복습

Race Condition (경합 조건): 여러 쓰레드가 동일한 메모리에 동시 접근할 때 발생. write가 문제임. Undefined Behavior가 발생함. 

해결법 : Lock, Atomic 


C++이 보증하는 기본 원칙 : atomic 연산에 한해 모든 쓰레드가 동일 객체에 대해 동일한 수정 순서를 관찰한다.

이게 무슨 소리인가?

atomic 연산

동일 객체란 그냥 하나의 메모리 공간, 변수 쯤으로 생각하면 된다.

동일한 수정 순서란 

 

atomic:: is_lock_free() //lock을 걸 필요 없음(원자적으로 수정됨)
true : 원자적 수정.
false : 원자적 수정 안됨.

 

atomic의 메모리 정책

메모리 정책에 따라 가시성, 코드 재배치 문젲가 해결되거나 안되거나가 결정됨.

메모리 정책은 atomic의 함수들의 인자를 통해 정해줄 수 있음.

  • Sequentially Consistent(seq_cst) : 가시성, 코드 재배치 문제해결됨
  • Acquire-Release(consume, acquire, release, acq_rel) : acquire과 relase가 짝을 이루어 동작함. release 명령 이전의 명령들이 해당 명령 이후로 재배치 되는 것을 막음. 그리고 acquire 는 아래 명령이 위로 재배치 되는 것을 막고, release이전의 명령들이 acquire 명령 이후에 가시성이 보장됨. 
  • Relaxed(relaxed) : 컴파일러가 자유롭게 최적화 함. 코드 재배치, 가시성 문제 존재. 가장 기본 원칙만 보장함.

위로 갈수록 엄격하고 아래로 갈 수록 자유로운 정책이다. 기본적으로 Sequentially Consistent로 동작한다.

Relaxed 정책은 멀티 쓰레드에서 문제를 일으킬 가능성이 있기 때문에 별로 사용하지는 않는다. 장점은 최적화가 잘 된다는 점 정도이다.

그런데 사실 인텔, AMD 칩은 애초에 순차적 일관성을 보장해서 Sequentially Consistent 정책을 사용해도 별다른 성능 차이가 없다. 그러므로 그냥 seq_cst를 사용하는 것이 바람직하다. (ARM 의 경우는 꽤 유의미한 성능 차이가 있을 수 있다고 함)

 

e.g) num.store(1,memory_order::memory_order_seq_cst);

 

compare_exchange_strong과 compare_eschange_weak의 차이:
flag와 expected를 비교하는 것이 어떤 이유로 인해 실패할 수 있음. (가짜 실패라고 함. Spurious Failure) 
strong은 성공할 때 까지 반복실행함. weak은 그러지 않음.

 

메모리 배리어
atomic_thread_fence() : 
Acquire-Release 정책처럼 명령 재배치와 가시성 문제를 해결하는 방법.

 

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

STL 컨테이너별 간략 특징 정리  (0) 2022.02.21
TLS(Thread Local Storage)  (0) 2022.02.01
Futrue  (0) 2022.01.27
조건 변수(Condition Variable)  (0) 2022.01.27
멀티 쓰레드 Lock 구현  (0) 2022.01.26