원자 비트 OR: atomic_fetch_or(C11)
원자 비트 OR: atomic_fetch_or(C11)
원자 정수에서 특정 비트를 '켜는'(설정하는) 작업은 비트 OR로 해요. 그런데 여러 스레드가 같은 정수를 동시에 건드리면 경쟁이 생길 수 있으니, 이 작업도 원자적으로 수행해야 안전하죠. 그 역할을 하는 함수가 **atomic_fetch_or**예요. fetch가 붙은 것처럼 이전 값을 돌려받는 게 특징입니다.
출처: cppreference
본문
시그니처
<stdatomic.h> 헤더에 정의돼 있어요.
| 형태 | 주석 |
|---|---|
C atomic_fetch_or(volatile A* obj, M arg); |
(1) C11부터 |
C atomic_fetch_or_explicit(volatile A* obj, M arg, memory_order order); |
(2) C11부터 |
동작 방식
obj가 가리키는 값과 arg를 비트 단위 OR한 결과로 그 값을 원자적으로 교체해요. 그리고 obj가 이전에 담고 있던 값을 반환해요. read-modify-write 연산이에요. (1) 버전은 memory_order_seq_cst로, (2) 버전은 order로 메모리 접근을 정렬해요.
이 함수는 모든 원자 객체 타입 A에 대해 정의된 제네릭 함수예요. 인자는 volatile 원자 타입의 포인터라서 비휘발성·휘발성(예: 메모리 매핑 I/O) 원자 객체의 주소를 모두 받아들여요. M은 A가 원자 정수 타입이면 A에 대응하는 비원자 타입이고, A가 원자 포인터 타입이면 ptrdiff_t예요.
제네릭 함수의 이름이 매크로인지 외부 연결을 가진 식별자인지는 규정되지 않았어요. 매크로 정의를 막고 실제 함수에 접근하려고 (atomic_fetch_or)(...)처럼 괄호로 감싸 쓰는 경우, 또는 프로그램이 제네릭 함수 이름과 같은 외부 식별자를 정의하는 경우의 동작은 미정의(undefined)예요.
매개변수
| 매개변수 | 설명 |
|---|---|
obj |
수정할 원자 객체를 가리키는 포인터 |
arg |
원자 객체에 저장된 값에 비트 OR할 값 |
order |
이 연산의 메모리 동기화 순서. 모든 값 허용 |
반환값
obj가 이전에 담고 있던 값을 반환해요.
예제
원자 플래그 정수에서 특정 비트를 켜는 전형적인 사용이에요. 상태 비트를 나타내는 플래그 값에 atomic_fetch_or(&flags, 1U << n)처럼 쓰면 n번째 비트만 안전하게 1로 설정돼요. 이전 값을 돌려받는 성질 덕분에 '바꾸기 전에 어떤 상태였는지'를 기록한 채 작업할 수 있습니다.
더 알아보기
atomic_fetch_and,atomic_fetch_xor: 원자 비트 AND·XOR.memory_order: 메모리 동기화 순서.atomic_fetch_add,atomic_fetch_sub: 원자 증감 연산.