10_atomic의 수정 순서

10_atomic의 수정 순서

날짜
생성자
ShalomShalom
카테고리
작성일
2023년 05월 15일
태그
atomic 연산에 한하여서 모든 쓰레드는 동일 객체동일한 수정 순서를 관찰할 수 있다.

동일한 수정 순서

  1. atomic 연산이란 CPU 입장에서 한번에 처리할 수 있는 연산을 말한다.
  1. 만약, 2-1-6-7-3 순으로 값이 수정이 되었다면, 7이 관찰된 시점에서 앞으로 2, 1, 6으로 관찰은 될 수 없음을 의미한다.

원자적 수정 예시

예를 들어 x32 비트의 환경에서 i64 타입에 값을 넣는다 했을 때
내부에선 32 bit, 32 bit 두개의 쪼개질 수 있는 타입인 i64에 값을 넣는 것이므로, 원자적 연산이 될 수 없다.
atomic<i64> 이지만 원자적인 연산을 할 수 없다.

동일 객체

만약 atomic<i64> 타입에 num1, num2가 있다고 하자
num1.store(1); num2.store(2);
위 코드에 num1이 먼저 1이 store 되고
그 다음에 num2에 2가 store가 되도록 코드를 짰다고해서
이 순서가 코드 재배치로 인해 바뀔수도 있다는 것이다.

Atomic 자세히

int main() { atomic<bool> flag = false; flag.store(true); // 1 flag.store(true, memory_order::memory_order_seq_cst); // 2 bool val = flag.load(memory_order::memory_order_seq_cst); //3 bool val = flag.load(); // 4 }
위의 코드에서 1번은 2번 코드의 함축이다.
3번은 4번의 함축된 코드다
default는 memory_order::memory_order_seq_cst라는 것
memory_order는 메모리 정책을 이야기한다.

다음은 원자적인 연산일까?

atomic<bool> flag = false; int main() { bool prev = flag.load(); fool.store(true); }
그렇지 않다, 왜냐하면 2개의 라인으로 코드가 작성이 되어있고, 2번째 라인에 갔을 때 다른 스레드에서 값이 변했을 수도 있기때문이다.
따라서 다음과 같이 코드를 수정할 수 있다.
atomic<bool> flag = false; int main() { bool prev = flag.exchange(true); }

CAS(Compare and swap)

atomic<bool> flag = false; int main() { bool expected = false; bool desired = true; // 이 라인은 아래 내용을 원자적 연산으로 진행한다. flag.compare_exchange_strong(expected, desired); if (flag == expected) { flag = desired; return true; } else { expected = flag; return false; } }
  • compare_exchange_weak는 다른 쓰레드의 interruption의 영향으로 중간에 실패할 수 있음
  • compare_exchange_stron은 다른 쓰레드의 interruption의 영향으로 중간에 실패한다면 다시 시도한다

Memory Order

  1. Sequentialy Consistent (seq_ct)
  1. Acquire-Release (acquire, release)
  1. Relaxed (relaxed)
1번은 코드 재배치가 일어나지 않음 (컴파일러에서 최적화 여지가 적음 = 직관적) Intel은 딱히 부하가 없다, 하지만 ARM계열 CPU는 과부하가 있다는 썰이 있다.
2번은 release의 경우 이전의 명령들이 해당 라인 이후로 재배치 되는 것은 금지 acquire와 release로 범위를 주면 해당 범위는 가시성이 보장이 된다.
some_value++; // 가시성 미보장 something.stroe(true, memory_order::memory_order_release) some_value++; // 가시성 보장 some_value++; // 가시성 보장 something.stroe(true, memory_order::memory_order_acquire) some_value++; // 가시성 미보장
3번은 코드재배치의 여지가 많다

댓글

guest