Pertanyaan Apakah `volatile` diperlukan untuk penguncian double-checked di Java tetapi tidak C #?


Ini sangat terkenal di antara programmer Java yang agar penguncian double-checked berfungsi dengan benar, variabel harus dinyatakan volatile, dan sinkronisasi inisialisasi objek tidak cukup.

Kesadaran mungkin sebagian besar karena semantik dari volatile kata kunci diubah dalam 1,5 untuk menyertakan hubungan "yang terjadi sebelum", setidaknya sebagian untuk membuat penguncian yang dikosongkan secara aman; dari apa yang saya pahami, hubungan "yang terjadi sebelum" berarti menulis ke variabel volatil menyebabkan semua variabel cache dalam utas ditulis ke memori utama, dan setelah membaca dari variabel volatil, semua variabel yang di-cache dianggap basi, dan harus dibaca ulang dari memori utama, sehingga semua yang ditulis sebelum menulis ke variabel volatil dijamin "terjadi sebelum" yang kemudian dibaca dari variabel itu.

Stack Overflow tampaknya percaya itu, untuk C #, volatile tidak diperlukan untuk penguncian double-checked (meskipun ada kekhawatiran bahwa ini mungkin khusus untuk CPU tertentu atau untuk implementasi Microsoft), sementara juga percaya bahwa semantik Java synchronized pernyataan itu persis sama sebagai C # lock pernyataan, yang menunjukkan bahwa masalah yang sama diidentifikasi di Jawa juga akan ada untuk C #, kecuali beberapa perbedaan besar lainnya ada di semantik penguncian ganda antara dua bahasa.

Jadi ... mana yang benar? Apakah penguncian double-checked di C # sebenarnya kurang berbahaya daripada di Java? Jika demikian, apa yang semantik bahasa berbeda untuk membuat kasus itu?

Jika tidak, apa yang secara khusus bisa salah tanpa volatile? Apakah semantik dari volatile di C # membuat hubungan "terjadi-sebelum" seperti Java, sehingga penguncian yang diperiksa dua kali sama amannya dengan C # volatile seperti di Jawa sejak 1,5?


5
2018-04-15 00:01


asal


Jawaban:


Dari MSDN: "Kata kunci yang mudah menguap menunjukkan bahwa bidang dapat dimodifikasi oleh beberapa utas yang sedang dieksekusi pada waktu yang sama. Bidang yang dinyatakan tidak stabil tidak tunduk pada pengoptimalan kompilator yang mengasumsikan akses oleh utas tunggal. Hal ini memastikan bahwa yang paling maksimal adalah nilai-tanggal hadir di lapangan setiap saat. "

Jadi, volatile hanya berguna jika Anda mengubah nilai variabel dari beberapa utas. Jika Anda mengunci () area kode yang mengakses sumber daya bersama dengan objek pengunci yang sama, Anda dijamin bahwa hanya satu utas yang dapat mengakses area kode tersebut secara bersamaan, maka tidak mudah menguap kecuali Anda memodifikasi objek pengunci (yang merupakan ide yang sangat buruk) .


2
2018-04-15 00:18