Namespaces
Variants

std:: atomic_thread_fence

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
atomic_thread_fence
(C++11)
Free functions for atomic operations
Free functions for atomic flags
헤더 파일에 정의됨 <atomic>
extern "C" void atomic_thread_fence ( std:: memory_order order ) noexcept ;
(C++11부터)

비원자적 및 릴랙스드 원자적 접근들의 메모리 동기화 순서 order 에 지정된 대로 설정합니다. 단, 아래에서 설명하는 바와 같이 동기화를 설정하기 위해서는 최소한 하나의 원자적 연산이 필요합니다.

목차

펜스-원자적 동기화

스레드 A 의 릴리스 펜스 F 는 다음 조건에서 스레드 B 의 원자적 acquire operation Y 와 동기화됩니다

  • 원자적 저장 연산 X 가 존재하며 (어떤 메모리 순서를 사용하든),
  • Y X 에 의해 기록된 값을 읽고 (또는 X 가 릴리스 연산이었다면 X 로 시작하는 릴리스 시퀀스 에 의해 기록될 값),
  • 스레드 A 에서 F X 보다 먼저 순서화됨.

이 경우, 스레드 A 에서 F sequenced-before 관계에 있는 모든 비-원자적 저장 및 relaxed 원자적 저장은 Y 이후에 스레드 B 에서 동일한 위치에 대해 수행되는 모든 비-원자적 로드 및 relaxed 원자적 로드에 대해 happen-before 관계를 가집니다.

원자적 펜스 동기화

원자적 release operation X 가 스레드 A 에서 수행되고, acquire fence F 가 스레드 B 에서 수행될 때, 다음 조건이 만족되면

  • 원자적 읽기 연산 Y 가 존재하며 (어떤 메모리 순서로든),
  • Y X 에 의해 기록된 값(또는 X로 시작하는 릴리스 시퀀스 에 의해 기록된 값)을 읽고,
  • Y 가 스레드 B 내에서 F 보다 먼저 순서화됩니다.

이 경우, 스레드 A 에서 X sequenced-before 관계에 있는 모든 비-원자적 및 relaxed 원자적 저장 연산들은 F 이후에 스레드 B 에서 동일한 위치들에 대해 수행되는 모든 비-원자적 및 relaxed 원자적 적재 연산들에 대해 happen-before 관계를 가집니다.

펜스-펜스 동기화

릴리스 펜스 FA 가 스레드 A 에서 획득 펜스 FB 와 스레드 B 에서 동기화되는 조건은 다음과 같습니다:

  • 원자적 객체 M 이 존재하고,
  • 스레드 A 에서 M 을 수정하는 원자적 쓰기 연산 X (어떤 메모리 순서로든)가 존재하며,
  • 스레드 A 에서 FA X 보다 sequenced-before 관계에 있고,
  • 스레드 B 에서 원자적 읽기 연산 Y (어떤 메모리 순서로든)가 존재하며,
  • Y X 에 의해 쓰여진 값을 읽고 (또는 X 가 release 연산이었다면 X 로 시작하는 release sequence 에 의해 쓰여질 값),
  • 스레드 B 에서 Y FB 보다 sequenced-before 관계에 있습니다.

이 경우, 스레드 A 에서 FA sequenced-before 관계에 있는 모든 비-원자적 및 relaxed 원자적 저장 연산들은 스레드 B 에서 FB 이후에 동일한 메모리 위치에 대해 수행되는 모든 비-원자적 및 relaxed 원자적 읽기 연산들에 대해 happen-before 관계를 가집니다.

order 매개변수의 값에 따라, 이 호출의 효과는 다음과 같습니다:

매개변수

order - 이 펜스에 의해 실행되는 메모리 순서

참고 사항

x86( x86-64 포함)에서, atomic_thread_fence 함수들은 CPU 명령어를 생성하지 않으며 컴파일 타임 코드 이동에만 영향을 미칩니다. 단, std :: atomic_thread_fence ( std:: memory_order_seq_cst ) 는 예외입니다.

atomic_thread_fence 는 동일한 std::memory_order 를 사용하는 atomic store 연산보다 더 강력한 동기화 제약을 부과합니다. atomic store-release 연산이 선행하는 모든 읽기 및 쓰기 연산이 store-release를 지나 이동하는 것을 방지하는 반면, atomic_thread_fence std:: memory_order_release 순서를 사용할 경우, 선행하는 모든 읽기 및 쓰기 연산이 이후의 모든 저장 연산을 지나 이동하는 것을 방지합니다.

펜스-펜스 동기화는 여러 개의 완화된 원자 연산 시퀀스에 동기화를 추가하는 데 사용할 수 있습니다, 예를 들어:

// 전역
std::string computation(int);
void print(std::string);
std::atomic<int> arr[3] = {-1, -1, -1};
std::string data[1000]; //비원자적 데이터
// 스레드 A, 3개의 값을 계산
void ThreadA(int v0, int v1, int v2)
{
//  assert(0 <= v0, v1, v2 < 1000);
    data[v0] = computation(v0);
    data[v1] = computation(v1);
    data[v2] = computation(v2);
    std::atomic_thread_fence(std::memory_order_release);
    std::atomic_store_explicit(&arr[0], v0, std::memory_order_relaxed);
    std::atomic_store_explicit(&arr[1], v1, std::memory_order_relaxed);
    std::atomic_store_explicit(&arr[2], v2, std::memory_order_relaxed);
}
// 스레드 B, 이미 계산된 0~3개의 값을 출력
void ThreadB()
{
    int v0 = std::atomic_load_explicit(&arr[0], std::memory_order_relaxed);
    int v1 = std::atomic_load_explicit(&arr[1], std::memory_order_relaxed);
    int v2 = std::atomic_load_explicit(&arr[2], std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_acquire);
//  v0, v1, v2는 -1이거나 일부 또는 모두 값이 있을 수 있음
//  그렇지 않으면 펜스로 인해 비원자적 데이터를 읽는 것이 안전함:
    if (v0 != -1)
        print(data[v0]);
    if (v1 != -1)
        print(data[v1]);
    if (v2 != -1)
        print(data[v2]);
}

예제

메일박스 배열을 스캔하고, 우리에게 할당된 메일박스만을 불필요한 동기화 없이 처리합니다. 이 예제는 atomic-fence 동기화를 사용합니다.

const int num_mailboxes = 32;
std::atomic<int> mailbox_receiver[num_mailboxes];
std::string mailbox_data[num_mailboxes];
// 작성자 스레드는 비원자적 공유 데이터를 업데이트한 후
// 다음과 같이 mailbox_receiver[i]를 업데이트합니다:
mailbox_data[i] = ...;
std::atomic_store_explicit(&mailbox_receiver[i], receiver_id, std::memory_order_release);
// 읽기 스레드는 모든 mailbox[i]를 확인해야 하지만 하나와만 동기화하면 됩니다.
for (int i = 0; i < num_mailboxes; ++i)
    if (std::atomic_load_explicit(&mailbox_receiver[i],
        std::memory_order_relaxed) == my_id)
    {
        // 하나의 작성자와만 동기화
        std::atomic_thread_fence(std::memory_order_acquire);
        // atomic_store_explicit() 이전에 작성자 스레드에서 수행된 모든 작업을
        // 관찰할 수 있음이 보장됨
        do_work(mailbox_data[i]);
    }

참고 항목

주어진 원자적 연산에 대한 메모리 순서 제약 조건을 정의함
(enum)
동일한 스레드에서 실행되는 스레드와 시그널 핸들러 간의 펜스
(function)
C documentation for atomic_thread_fence