원자 값 교환: atomic_exchange(C11)
원자 값 교환: atomic_exchange(C11)
원자 객체의 값을 새 값으로 바꾸면서, 바꾸기 전에 담겨 있던 이전 값을 돌려받고 싶을 때가 있어요. 스레드가 상태 플래그 하나를 이리저리 넘겨받을 때 자주 쓰는 패턴이죠. 이 두 가지를 한 번에 원자적으로 처리해 주는 함수가 **atomic_exchange**예요.
출처: cppreference
본문
시그니처
<stdatomic.h> 헤더에 정의돼 있어요.
| 형태 | 주석 |
|---|---|
C atomic_exchange(volatile A* obj, C desired); |
(1) C11부터 |
C atomic_exchange_explicit(volatile A* obj, C desired, memory_order order); |
(2) C11부터 |
동작 방식
obj가 가리키는 값을 desired로 원자적으로 바꾸고, 그전에 obj가 담고 있던 값을 반환해요. read-modify-write 연산이에요. (1) 버전은 memory_order_seq_cst로, (2) 버전은 order로 메모리 접근을 정렬해요.
이 함수는 모든 원자 객체 타입 A에 대해 정의된 제네릭 함수예요. 인자는 volatile 원자 타입의 포인터라서 비휘발성·휘발성(예: 메모리 매핑 I/O) 원자 객체의 주소를 모두 받아들여요. C는 A에 대응하는 비원자 타입이에요.
제네릭 함수의 이름이 매크로인지 외부 연결을 가진 식별자인지는 규정되지 않았어요. 매크로 정의를 막고 실제 함수에 접근하려고 (atomic_exchange)(...)처럼 괄호로 감싸 쓰는 경우, 또는 프로그램이 제네릭 함수 이름과 같은 외부 식별자를 정의하는 경우의 동작은 미정의(undefined)예요.
매개변수
| 매개변수 | 설명 |
|---|---|
obj |
수정할 원자 객체를 가리키는 포인터 |
desired |
원자 객체를 교체할 값 |
order |
이 연산의 메모리 동기화 순서. 모든 값 허용 |
반환값
obj가 이전에 담고 있던 값을 반환해요.
예제
원자 정수에 차례대로 새 값을 저장하면서, 교환 전의 값을 돌려받는 모습을 상상해 볼게요. 예를 들어 어떤 원자 상태 변수의 값을 바꾸되, 바꾸기 전에 무엇이었는지를 기록으로 남기고 싶다면 atomic_exchange가 이전 값을 돌려주기 때문에 그대로 쓸 수 있어요. 조건부로 바꾸고 싶다면 이 함수 대신 atomic_compare_exchange 계열을 써야 합니다.
더 알아보기
atomic_compare_exchange: 기대값이 맞을 때만 교환.atomic_fetch_add등atomic_fetch_*: 값을 계산해 저장하고 이전 값을 반환.memory_order: 메모리 동기화 순서.