मैं सी 11 मानक की धारा 5.1.2.4 के साथ संघर्ष कर रहा हूं, विशेष रूप से रिलीज़ / एक्वायर का शब्दार्थ। मैं ध्यान देता हूं कि 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) ;
इसलिए, मैं r1 == 1 के लिए थ्रेड "1" और r2 = 4 के लिए थ्रेड "2" की अपेक्षा करूंगा।
मैं उम्मीद करूंगा कि क्योंकि (संप्रदाय 16 और 18 संप्रदाय 5.1.2.4 का अनुसरण करता है):
- सभी (परमाणु नहीं) पढ़ता है और लिखता है "पहले से अनुक्रमित है" और इसलिए "परमाणु लेखन / रिलीज से पहले" धागे में "1" होता है,
- जो "अंतर-धागा-होता है-उससे पहले" परमाणु "/ 2 धागे में प्राप्त" (जब यह 'सत्य' पढ़ता है),
- जो बदले में "पहले से अनुक्रमित" है और इसलिए "परमाणु से पहले" होता है (ना कि परमाणु) पढ़ता है और लिखता है (थ्रेड "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
और बशर्ते कि आर 1 और एक्स 1 उस क्रम में हो, इससे मुझे अपेक्षित परिणाम मिलता है।
लेकिन 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
। तो आपका कंपाइलर आपके कोड (कितनी आश्चर्यजनक) का सही अनुवाद कर रहा है, जैसे कि आपका कोड प्रभावी रूप से पूरी तरह से अनुक्रमिक है और कुछ भी दिलचस्प नहीं है।