Saya telah mendengarkan dan membaca beberapa artikel, pembicaraan, dan pertanyaan tentang stackoverflow std::atomic
, dan saya ingin memastikan bahwa saya telah memahaminya dengan baik. Karena saya masih agak bingung dengan garis cache menulis visibilitas karena kemungkinan keterlambatan protokol koherensi cache MESI (atau diturunkan), menyimpan buffer, antrian tidak valid, dan sebagainya.
Saya membaca x86 memiliki model memori yang lebih kuat, dan bahwa jika invalidasi cache tertunda x86 dapat mengembalikan operasi yang dimulai. Tapi saya sekarang hanya tertarik pada apa yang saya anggap sebagai programmer C ++, terlepas dari platform.
[T1: thread1 T2: thread2 V1: variabel atom bersama]
Saya mengerti bahwa std :: atomic menjamin bahwa,
(1) Tidak ada ras data yang terjadi pada variabel (berkat akses eksklusif ke baris cache).
(2) Bergantung pada memory_order mana yang kami gunakan, itu menjamin (dengan penghalang) bahwa konsistensi berurutan terjadi (sebelum penghalang, setelah penghalang atau keduanya).
(3) Setelah penulisan atom (V1) pada T1, atom RMW (V1) pada T2 akan koheren (garis cache-nya akan diperbarui dengan nilai tertulis pada T1).
Tetapi sebagai primer koherensi cache menyebutkan,
Implikasi dari semua hal ini adalah, secara default, banyak yang dapat mengambil data basi (jika permintaan invalidasi yang sesuai berada di antrian invalidation)
Jadi, apakah yang berikut ini benar?
(4) std::atomic
TIDAK menjamin bahwa T2 tidak akan membaca nilai 'basi' pada pembacaan atom (V) setelah penulisan atom (V) pada T1.
Pertanyaan jika (4) benar: jika penulisan atom pada T1 membatalkan garis cache tidak peduli penundaan, mengapa T2 menunggu pembatalan efektif ketika operasi atom RMW tetapi tidak pada atom membaca?
Pertanyaan jika (4) salah: kapan thread dapat membaca nilai 'basi' dan "itu terlihat" dalam eksekusi, lalu?
Saya sangat menghargai jawaban Anda
Perbarui 1
Jadi sepertinya saya salah pada (3) saat itu. Bayangkan interleave berikut, untuk V1 awal = 0:
T1: W(1)
T2: R(0) M(++) W(1)
Meskipun RM2 T2 dijamin terjadi sepenuhnya setelah W (1) dalam kasus ini, TW masih bisa membaca nilai 'basi' (saya salah). Menurut ini, atom tidak menjamin koherensi cache penuh, hanya konsistensi berurutan.
Perbarui 2
(5) Sekarang bayangkan contoh ini (x = y = 0 dan bersifat atomik):
T1: x = 1;
T2: y = 1;
T3: if (x==1 && y==0) print("msg");
sesuai dengan apa yang telah kita bicarakan, melihat "msg" yang ditampilkan di layar tidak akan memberi kita informasi di luar T2 yang dieksekusi setelah T1. Jadi salah satu dari eksekusi berikut mungkin terjadi:
- T1 <T3 <T2
- T1 <T2 <T3 (di mana T3 melihat x = 1 tetapi belum y = 1)
Apakah itu benar?
(6) Jika utas selalu dapat membaca nilai 'basi', apa yang akan terjadi jika kami mengambil skenario "publikasikan" tetapi alih-alih memberi isyarat bahwa beberapa data siap, kami melakukan yang sebaliknya (menghapus data)?
T1: delete gameObjectPtr; is_enabled.store(false, std::memory_order_release);
T2: while (is_enabled.load(std::memory_order_acquire)) gameObjectPtr->doSomething();
di mana T2 masih akan menggunakan ptr yang dihapus sampai melihat bahwa is_enabled adalah salah.
(7) Juga, fakta bahwa utas dapat membaca nilai 'basi' berarti bahwa mutex tidak dapat diimplementasikan hanya dengan satu atom bebas kunci, bukan? Itu akan membutuhkan mekanisme sinkronisasi antara utas. Apakah itu membutuhkan atom yang dapat dikunci?