C11 표준의 5.1.2.4 섹션, 특히 Release / Acquire의 의미론으로 어려움을 겪고 있습니다. 나는주의 https://preshing.com/20120913/acquire-and-release-semantics/ (다른 사람의 사이가) 그 상태 :
... 릴리스 시맨틱은 프로그램 순서에서 선행하는 읽기 또는 쓰기 조작으로 쓰기 릴리스의 메모리 순서가 변경되지 않도록합니다.
따라서 다음을 위해
typedef struct test_struct
{
_Atomic(bool) ready ;
int v1 ;
int v2 ;
} test_struct_t ;
extern void
test_init(test_struct_t* ts, int v1, int v2)
{
ts->v1 = v1 ;
ts->v2 = v2 ;
atomic_store_explicit(&ts->ready, false, memory_order_release) ;
}
extern int
test_thread_1(test_struct_t* ts, int v2)
{
int v1 ;
while (atomic_load_explicit(&ts->ready, memory_order_acquire)) ;
ts->v2 = v2 ; // expect read to happen before store/release
v1 = ts->v1 ; // expect write to happen before store/release
atomic_store_explicit(&ts->ready, true, memory_order_release) ;
return v1 ;
}
extern int
test_thread_2(test_struct_t* ts, int v1)
{
int v2 ;
while (!atomic_load_explicit(&ts->ready, memory_order_acquire)) ;
ts->v1 = v1 ;
v2 = ts->v2 ; // expect write to happen after store/release in thread "1"
atomic_store_explicit(&ts->ready, false, memory_order_release) ;
return v2 ;
}
그것들이 실행되는 곳 :
> in the "main" thread: test_struct_t ts ;
> test_init(&ts, 1, 2) ;
> start thread "2" which does: r2 = test_thread_2(&ts, 3) ;
> start thread "1" which does: r1 = test_thread_1(&ts, 4) ;
따라서 스레드 "1"에 r1 == 1이 있고 스레드 "2"에 r2 = 4가있을 것으로 예상합니다.
나는 (5.1.2.4의 16 항과 18 항에 따름)
- 모든 (원자 아님) 읽기 및 쓰기는 "이전 순서"로되어 있으므로 "1"스레드의 원자 쓰기 / 해제 "전에"발생합니다.
- 스레드 "2"의 원자 읽기 / 획득 ( 'true'를 읽을 때)
- 이것은 "이전에 순서화"되고 따라서 "원자가 아닌" "스레드 전에"읽고 (쓰레드 "2"에서) 쓴다.
그러나 표준을 이해하지 못했을 수도 있습니다.
x86_64 용으로 생성 된 코드는 다음과 같습니다.
test_thread_1:
movzbl (%rdi),%eax -- atomic_load_explicit(&ts->ready, memory_order_acquire)
test $0x1,%al
jne <test_thread_1> -- while is true
mov %esi,0x8(%rdi) -- (W1) ts->v2 = v2
mov 0x4(%rdi),%eax -- (R1) v1 = ts->v1
movb $0x1,(%rdi) -- (X1) atomic_store_explicit(&ts->ready, true, memory_order_release)
retq
test_thread_2:
movzbl (%rdi),%eax -- atomic_load_explicit(&ts->ready, memory_order_acquire)
test $0x1,%al
je <test_thread_2> -- while is false
mov %esi,0x4(%rdi) -- (W2) ts->v1 = v1
mov 0x8(%rdi),%eax -- (R2) v2 = ts->v2
movb $0x0,(%rdi) -- (X2) atomic_store_explicit(&ts->ready, false, memory_order_release)
retq
그리고 제공 R1 및 X1은 순서대로 일어날 것으로, 이것은 내가 기대하는 결과를 제공합니다.
그러나 x86_64에 대한 나의 이해는 다른 읽기와 함께 읽기가 순서대로 발생하고 다른 쓰기와 함께 쓰기가 순서대로 이루어 지지만 읽기와 쓰기가 순서대로 이루어지지 않을 수 있다는 것입니다. 이것은 X1이 R1 이전에 일어날 수 있고 심지어 X1, X2, W2, R1이 그 순서대로 일어날 수 있음을 의미합니다. [이것은 필사적으로 보이지 않지만 R1이 일부 캐시 문제에 의해 유지된다면?]
제발 : 이해가 안되나요?
의로드 / 스토어를 ts->ready
로 변경하면 스토어에 memory_order_seq_cst
대해 생성 된 코드는 다음과 같습니다.
xchg %cl,(%rdi)
이것은 x86_64에 대한 나의 이해와 일치하며 내가 기대하는 결과를 줄 것입니다.
8.2.3.3 Stores Are Not Reordered With Earlier Loads
. 따라서 컴파일러는 코드가 올바르게 완전히 번역되어 (놀랍습니다) 코드가 효과적으로 순차적이며 흥미로운 것은 동시에 발생하지 않습니다.