원자 비트 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) 원자 객체의 주소를 모두 받아들여요. MA가 원자 정수 타입이면 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: 원자 증감 연산.