원자 비트 AND: atomic_fetch_and(C11)

원자 비트 AND: atomic_fetch_and(C11)

원자 정수에서 특정 비트를 '꺼내는'(끄는) 작업을 하고 싶다면 비트 AND를 써요. 그런데 이 작업도 여러 스레드가 동시에 하면 경쟁이 생길 수 있으니 원자적으로 해야 안전하죠. 그 역할을 하는 함수가 **atomic_fetch_and**예요. 이름에 fetch가 들어간 것처럼 이전 값을 돌려받는 게 특징입니다.

출처: cppreference

본문

시그니처

<stdatomic.h> 헤더에 정의돼 있어요.

형태 주석
C atomic_fetch_and(volatile A* obj, M arg); (1) C11부터
C atomic_fetch_and_explicit(volatile A* obj, M arg, memory_order order); (2) C11부터

동작 방식

obj가 가리키는 값과 arg를 비트 단위 AND한 결과로 그 값을 원자적으로 교체해요. 그리고 obj가 이전에 담고 있던 값을 반환해요. read-modify-write 연산이에요. (1) 버전은 memory_order_seq_cst로, (2) 버전은 order로 메모리 접근을 정렬해요.

이 함수는 모든 원자 객체 타입 A에 대해 정의된 제네릭 함수예요. 인자는 volatile 원자 타입의 포인터라서 비휘발성·휘발성(예: 메모리 매핑 I/O) 원자 객체의 주소를 모두 받아들여요. MA가 원자 정수 타입이면 A에 대응하는 비원자 타입이고, A가 원자 포인터 타입이면 ptrdiff_t예요.

제네릭 함수의 이름이 매크로인지 외부 연결을 가진 식별자인지는 규정되지 않았어요. 매크로 정의를 막고 실제 함수에 접근하려고 (atomic_fetch_and)(...)처럼 괄호로 감싸 쓰는 경우, 또는 프로그램이 제네릭 함수 이름과 같은 외부 식별자를 정의하는 경우의 동작은 미정의(undefined)예요.

매개변수

매개변수 설명
obj 수정할 원자 객체를 가리키는 포인터
arg 원자 객체에 저장된 값에 비트 AND할 값
order 이 연산의 메모리 동기화 순서. 모든 값 허용

반환값

obj가 이전에 담고 있던 값을 반환해요.

예제

원자 정수에서 특정 비트만 끄고 싶다면, 끄고 싶은 비트 위치를 ~로 반전시킨 arg를 AND하면 돼요. 예를 들어 하위 8비트만 남기고 싶다면 atomic_fetch_and(&flags, 0xFF)처럼 쓰는 식이에요. 단순히 값을 바꾸는 것뿐 아니라 진행 전의 플래그를 로그로 남기고 싶다면, 이 함수가 이전 값을 돌려주기 때문에 그대로 활용할 수 있어요.

더 알아보기

  • atomic_fetch_or, atomic_fetch_xor: 원자 비트 OR·XOR.
  • memory_order: 메모리 동기화 순서.
  • atomic_fetch_add, atomic_fetch_sub: 원자 증감 연산.