표준 라이브러리 헤더 <stdatomic.h>

표준 라이브러리 헤더 <stdatomic.h> (C11)

여러 스레드가 같은 변수를 동시에 건드리면 데이터 경쟁이 생겨요. _Atomic 타입은 이 문제를 언어 수준에서 풀지만, 매번 _Atomic이라고 쓰기보다 편리한 이름으로 쓰고 싶을 때가 많죠. <stdatomic.h>는 동시성 지원 라이브러리의 일부로, 원자 연산에 필요한 타입 별칭·함수·매크로를 제공해요. 원자 타입 선언 자체의 의미는 언어 수준의 원자 타입 문서와 함께 보면 좋아요.

출처: cppreference

본문

원자 연산(Atomic operations)

원자 타입에 대한 연산(Operations on atomic types)

이름 설명
ATOMIC_BOOL_LOCK_FREE, ATOMIC_CHAR_LOCK_FREE, ATOMIC_CHAR8_T_LOCK_FREE, ATOMIC_CHAR16_T_LOCK_FREE, ATOMIC_CHAR32_T_LOCK_FREE, ATOMIC_WCHAR_T_LOCK_FREE, ATOMIC_SHORT_LOCK_FREE, ATOMIC_INT_LOCK_FREE, ATOMIC_LONG_LOCK_FREE, ATOMIC_LLONG_LOCK_FREE, ATOMIC_POINTER_LOCK_FREE (C11) 주어진 원자 타입이 락프리(lock-free)인지 나타내는 매크로 상수
atomic_is_lock_free (C11) 원자 객체가 락프리인지 나타냄
atomic_store / atomic_store_explicit (C11) 원자 객체에 값을 저장
atomic_load / atomic_load_explicit (C11) 원자 객체에서 값을 읽음
atomic_exchange / atomic_exchange_explicit (C11) 원자 객체의 값과 교환
atomic_compare_exchange_strong, atomic_compare_exchange_strong_explicit, atomic_compare_exchange_weak, atomic_compare_exchange_weak_explicit (C11) 기대하는 값과 같으면 값을 교환하고, 다르면 기존 값을 읽음
atomic_fetch_add / atomic_fetch_add_explicit (C11) 원자 덧셈
atomic_fetch_sub / atomic_fetch_sub_explicit (C11) 원자 뺄셈
atomic_fetch_or / atomic_fetch_or_explicit (C11) 원자 비트 OR
atomic_fetch_xor / atomic_fetch_xor_explicit (C11) 원자 비트 배타적 OR
atomic_fetch_and / atomic_fetch_and_explicit (C11) 원자 비트 AND

플래그 타입과 연산(Flag type and operations)

이름 설명
atomic_flag (C11) 락프리 원자 불리언 플래그 구조체
atomic_flag_test_and_set / atomic_flag_test_and_set_explicit (C11) atomic_flagtrue로 설정하고 기존 값을 반환
atomic_flag_clear / atomic_flag_clear_explicit (C11) atomic_flagfalse로 설정

초기화(Initialization)

이름 설명
atomic_init (C11) 이미 존재하는 원자 객체를 초기화
ATOMIC_VAR_INIT (C11)(C17에서 폐기, C23에서 제거) 새 원자 객체를 초기화하는 함수 매크로
ATOMIC_FLAG_INIT (C11) 새 atomic_flag를 초기화하는 매크로 상수

메모리 동기화 순서(Memory synchronization ordering)

이름 설명
memory_order (C11) 메모리 순서 제약을 정의하는 열거형
kill_dependency (C11) memory_order_consume을 위한 의존성 체인을 끊는 함수 매크로
atomic_thread_fence (C11) 범용 메모리 순서 의존 펜스 동기화 원시 연산
atomic_signal_fence (C11) 같은 스레드 내 스레드와 신호 처리기 사이의 펜스

편의 타입 별칭(Convenience type aliases)

typedef 이름과 전체 타입 이름을 대응시키는 표예요. 실수로 _Atomic 키워드를 빠뜨리지 않게, 편의 별칭을 쓰면 기호 사용이 훨씬 간결해져요.

Typedef 이름 전체 타입 이름
atomic_bool (C11) _Atomic _Bool
atomic_char (C11) _Atomic char
atomic_schar (C11) _Atomic signed char
atomic_uchar (C11) _Atomic unsigned char
atomic_short (C11) _Atomic short
atomic_ushort (C11) _Atomic unsigned short
atomic_int (C11) _Atomic int
atomic_uint (C11) _Atomic unsigned int
atomic_long (C11) _Atomic long
atomic_ulong (C11) _Atomic unsigned long
atomic_llong (C11) _Atomic long long
atomic_ullong (C11) _Atomic unsigned long long
atomic_char8_t (C23) _Atomic char8_t
atomic_char16_t (C11) _Atomic char16_t
atomic_char32_t (C11) _Atomic char32_t
atomic_wchar_t (C11) _Atomic wchar_t
atomic_int_least8_t (C11) _Atomic int_least8_t
atomic_uint_least8_t (C11) _Atomic uint_least8_t
atomic_int_least16_t (C11) _Atomic int_least16_t
atomic_uint_least16_t (C11) _Atomic uint_least16_t
atomic_int_least32_t (C11) _Atomic int_least32_t
atomic_uint_least32_t (C11) _Atomic uint_least32_t
atomic_int_least64_t (C11) _Atomic int_least64_t
atomic_uint_least64_t (C11) _Atomic uint_least64_t
atomic_int_fast8_t (C11) _Atomic int_fast8_t
atomic_uint_fast8_t (C11) _Atomic uint_fast8_t
atomic_int_fast16_t (C11) _Atomic int_fast16_t
atomic_uint_fast16_t (C11) _Atomic uint_fast16_t
atomic_int_fast32_t (C11) _Atomic int_fast32_t
atomic_uint_fast32_t (C11) _Atomic uint_fast32_t
atomic_int_fast64_t (C11) _Atomic int_fast64_t
atomic_uint_fast64_t (C11) _Atomic uint_fast64_t
atomic_intptr_t (C11) _Atomic intptr_t
atomic_uintptr_t (C11) _Atomic uintptr_t
atomic_size_t (C11) _Atomic size_t
atomic_ptrdiff_t (C11) _Atomic ptrdiff_t
atomic_intmax_t (C11) _Atomic intmax_t
atomic_uintmax_t (C11) _Atomic uintmax_t

시그니처(Synopsis)

#define __STDC_VERSION_STDATOMIC_H__ 202311L

void atomic_init(volatile A* obj, /*C*/ value);
/*type*/ kill_dependency(/*type*/ y);
void atomic_thread_fence(memory_order order);
void atomic_signal_fence(memory_order order);
bool atomic_is_lock_free(const volatile A* obj);
void atomic_store(volatile A* object, /*C*/ desired);
void atomic_store_explicit(volatile A* object, /*C*/ desired, memory_order order);
/*C*/ atomic_load(const volatile A* object);
/*C*/ atomic_load_explicit(const volatile A* object, memory_order order);
/*C*/ atomic_exchange(volatile A* object, /*C*/ desired);
/*C*/ atomic_exchange_explicit(volatile A* object, /*C*/ desired, memory_order order);
bool atomic_compare_exchange_strong(volatile A* object, /*C*/* expected, /*C*/ desired);
bool atomic_compare_exchange_strong_explicit(volatile A* object, /*C*/* expected,
/*C*/ desired, memory_order success, memory_order failure);
bool atomic_compare_exchange_weak(volatile A* object, /*C*/* expected, /*C*/ desired);
bool atomic_compare_exchange_weak_explicit(volatile A* object, /*C*/* expected,
/*C*/ desired, memory_order success, memory_order failure);
/*C*/ /*atomic_fetch_key*/(volatile A* object, M operand);
/*C*/ /*atomic_fetch_key_explicit*/(volatile A* object, M operand, memory_order order);
bool atomic_flag_test_and_set(volatile atomic_flag* object);
bool atomic_flag_test_and_set_explicit(volatile atomic_flag* object,
 memory_order order);
void atomic_flag_clear(volatile atomic_flag* object);
void atomic_flag_clear_explicit(volatile atomic_flag* object,
 memory_order order);

여기서 A는 원자 타입, C는 그에 대응하는 비원자 타입, M은 산술·비트 연산의 피연산자 타입이에요. 실제 함수틀은 타입마다 구체화돼요. _explicit 버전은 메모리 순서(memory_order)를 직접 지정할 수 있고, 그냥 버전은 순차 일관(sequentially consistent) 순서를 사용해요.

더 알아보기

  • 원자 타입의 언어 수준 의미는 원자 타입(Atomic types) 문서를 봐요.
  • memory_order의 자세한 의미론은 메모리 순서 문서에서 확인해요.
  • 스레드 자체는 <threads.h>에서 다뤄요.