Namespaces
Variants

Atomic types

From cppreference.net

목차

구문

_Atomic ( type-name ) (1) (C11부터)
_Atomic type-name (2) (C11부터)
1) 타입 지정자로 사용; 이는 새로운 atomic 타입을 지정합니다
2) 타입 한정자로 사용; 이는 type-name 의 atomic 버전을 지정합니다. 이 역할에서는 const , volatile , 그리고 restrict 와 혼합하여 사용할 수 있지만, 다른 한정자들과 달리 type-name 의 atomic 버전은 다른 크기, 정렬 및 객체 표현을 가질 수 있습니다.
type-name - 배열이나 함수가 아닌 모든 타입. (1) 의 경우, type-name 은 atomic이나 cvr-qualified일 수 없음

헤더 파일 <stdatomic.h> 다양한 편의성 타입 별칭들 을 정의합니다. atomic_bool 부터 atomic_uintmax_t 까지의 이러한 별칭들은 내장 타입과 라이브러리 타입에서 이 키워드의 사용을 단순화합니다.

_Atomic const int* p1;  // p는 atomic const int를 가리키는 포인터입니다
const atomic_int* p2;   // 동일
const _Atomic(int)* p3; // 동일

매크로 상수 __STDC_NO_ATOMICS__ 가 컴파일러에 의해 정의된 경우, _Atomic 키워드는 제공되지 않습니다.

설명

원자적 타입의 객체들은 데이터 레이스 로부터 자유로운 유일한 객체입니다; 즉, 두 스레드에 의해 동시에 수정되거나 하나의 스레드에 의해 수정되고 다른 스레드에 의해 읽힐 수 있습니다.

각 원자 객체는 해당 객체에 대한 수정들의 전체 순서인 자체 수정 순서(modification order) 를 가집니다. 만약 어떤 스레드의 관점에서, 특정 원자 객체 M 의 수정 A 가 동일한 원자 객체 M 의 수정 B 보다 happens-before 관계에 있다면, M 의 수정 순서에서 A B 보다 앞서 발생합니다.

각 원자 객체는 자체적인 수정 순서를 가지지만, 단일한 전체 순서는 존재하지 않습니다. 서로 다른 스레드들은 서로 다른 원자 객체들에 대한 수정 사항을 다른 순서로 관찰할 수 있습니다.

모든 원자적 연산에 대해 보장되는 네 가지 일관성 종류가 있습니다:

  1. write-write coherence : 원자적 객체 M 을 수정하는 연산 A M 을 수정하는 연산 B 보다 happens-before 관계에 있다면, M 의 수정 순서에서 A B 보다 먼저 나타납니다.
  2. read-read coherence : 원자적 객체 M 의 값 계산 A M 의 값 계산 B 보다 happens before 관계에 있고, A M 에 대한 사이드 이펙트 X 로부터 값을 가져온다면, B 에 의해 계산된 값은 X 에 의해 저장된 값이거나, M 의 수정 순서에서 X 보다 나중에 나타나는 사이드 이펙트 Y 에 의해 저장된 값입니다.
  3. read-write coherence : 원자적 객체 M 의 값 계산 A M 에 대한 연산 B 보다 happens-before 관계에 있다면, A M 의 수정 순서에서 B 보다 먼저 나타나는 사이드 이펙트 X 로부터 값을 가져옵니다.
  4. write-read coherence : 원자적 객체 M 에 대한 사이드 이펙트 X M 의 값 계산 B 보다 happens-before 관계에 있다면, B 평가는 X 로부터 값을 가져오거나, M 의 수정 순서에서 X 보다 나중에 나타나는 사이드 이펙트 Y 로부터 값을 가져옵니다.

일부 원자적 연산은 동기화 연산이기도 합니다; 여기에는 추가적인 릴리스 의미론, 획득 의미론 또는 순차적 일관성 의미론이 있을 수 있습니다. memory_order 를 참조하십시오.

내장 증가 및 감소 연산자 복합 할당 연산자 는 완전한 순차적 일관성 순서를 갖는 읽기-수정-쓰기 원자 연산입니다 ( memory_order_seq_cst 를 사용하는 것처럼). 덜 엄격한 동기화 의미론이 필요한 경우, 대신 표준 라이브러리 함수 를 사용할 수 있습니다.

원자적 속성은 lvalue 표현식 에 대해서만 의미가 있습니다. Lvalue-to-rvalue 변환(원자적 위치에서 CPU 레지스터로의 메모리 읽기를 모델링함)은 다른 한정자와 함께 원자성을 제거합니다.

참고 사항

원자적 구조체/공용체의 멤버에 접근하는 것은 정의되지 않은 동작입니다.

라이브러리 타입 sig_atomic_t 는 스레드 간 동기화나 메모리 정렬을 제공하지 않으며, 원자성만을 제공합니다.

volatile 타입은 스레드 간 동기화, 메모리 정렬 또는 원자성을 제공하지 않습니다.

구현체는 C 언어의 _Atomic ( T ) 표현이 모든 가능한 타입 T 에 대해 C++의 std :: atomic < T > 표현과 동일하도록 보장하는 것이 권장됩니다. 원자성과 메모리 순서를 보장하는 메커니즘은 상호 호환되어야 합니다.

키워드

_Atomic

예제

#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>
atomic_int acnt;
int cnt;
int f(void* thr_data)
{
    for (int n = 0; n < 1000; ++n)
    {
        ++cnt;
        ++acnt;
        // for this example, relaxed memory order is sufficient, e.g.
        // atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed);
    }
    return 0;
}
int main(void)
{
    thrd_t thr[10];
    for (int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for (int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);
    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

가능한 출력:

The atomic counter is 10000
The non-atomic counter is 8644

참고문헌

  • C23 표준 (ISO/IEC 9899:2024):
  • 6.7.2.4 Atomic type specifiers (p: TBD)
  • 7.17 Atomics <stdatomic.h> (p: TBD)
  • C17 표준 (ISO/IEC 9899:2018):
  • 6.7.2.4 Atomic type specifiers (p: 87)
  • 7.17 Atomics <stdatomic.h> (p: 200-209)
  • C11 표준 (ISO/IEC 9899:2011):
  • 6.7.2.4 Atomic type specifiers (p: 121)
  • 7.17 Atomics <stdatomic.h> (p: 273-286)

참고 항목

동시성 지원 라이브러리