std:: atomic_thread_fence
|
헤더 파일에 정의됨
<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 == std:: memory_order_relaxed 일 때, 아무런 효과가 없습니다.
- order == std:: memory_order_acquire 또는 order == std:: memory_order_consume 일 때, acquire fence입니다.
- order == std:: memory_order_release 일 때, release fence입니다.
- order == std:: memory_order_acq_rel 일 때, release fence이자 acquire fence입니다.
- order == std:: memory_order_seq_cst 일 때, sequentially-consistent ordering acquire fence이자 release fence입니다.
매개변수
| 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]); }
참고 항목
|
(C++11)
|
주어진 원자적 연산에 대한 메모리 순서 제약 조건을 정의함
(enum) |
|
(C++11)
|
동일한 스레드에서 실행되는 스레드와 시그널 핸들러 간의 펜스
(function) |
|
C documentation
for
atomic_thread_fence
|
|