Terburuk (tidak akan bekerja)
Ubah pengubah akses counter
menjadipublic volatile
Seperti yang orang lain katakan, ini sendiri sebenarnya tidak aman sama sekali. Intinya volatile
adalah bahwa banyak utas yang berjalan pada banyak CPU dapat dan akan menyimpan data dan memesan kembali instruksi.
Jika tidak volatile
, dan CPU A menambah nilai, maka CPU B mungkin tidak benar-benar melihat nilai tambah itu sampai beberapa waktu kemudian, yang dapat menyebabkan masalah.
Jika ya volatile
, ini hanya memastikan dua CPU melihat data yang sama secara bersamaan. Itu tidak menghentikan mereka sama sekali dari interleaving membaca dan menulis operasi yang merupakan masalah yang Anda coba hindari.
Kedua terbaik:
lock(this.locker) this.counter++
;
Ini aman untuk dilakukan (asalkan Anda ingat ke lock
tempat lain yang Anda akses this.counter
). Ini mencegah utas lainnya dari mengeksekusi kode lain yang dijaga oleh locker
. Menggunakan kunci juga, mencegah masalah penyusunan ulang multi-CPU seperti di atas, yang sangat bagus.
Masalahnya adalah, pengunciannya lambat, dan jika Anda menggunakan kembali locker
di beberapa tempat lain yang tidak benar-benar terkait maka Anda dapat memblokir utas lainnya tanpa alasan.
Terbaik
Interlocked.Increment(ref this.counter);
Ini aman, karena secara efektif membaca, menambah, dan menulis dalam 'satu klik' yang tidak dapat diganggu. Karena itu, ini tidak akan memengaruhi kode lain, dan Anda tidak perlu ingat untuk mengunci di tempat lain juga. Ini juga sangat cepat (seperti yang dikatakan MSDN, pada CPU modern, ini seringkali secara harfiah merupakan instruksi CPU tunggal).
Namun saya tidak sepenuhnya yakin apakah itu bisa mengatasi hal-hal penataan ulang CPU lain, atau jika Anda juga perlu menggabungkan volatile dengan kenaikan.
Catatan Interlocked:
- METODE TERKAIT DENGAN AMAN SAATNYA PADA SETIAP JUMLAH INTI ATAU CPU.
- Metode yang saling bertautan menerapkan pagar penuh di sekitar instruksi yang mereka jalankan, sehingga pemesanan ulang tidak terjadi.
- Metode yang saling bertautan tidak perlu atau bahkan tidak mendukung akses ke bidang volatil , karena volatil ditempatkan setengah pagar di sekitar operasi pada bidang yang diberikan dan saling terkait menggunakan pagar penuh.
Catatan kaki: Apa volatile sebenarnya baik untuk.
Karena volatile
tidak mencegah masalah multithreading semacam ini, untuk apa? Contoh yang baik adalah mengatakan Anda memiliki dua utas, satu yang selalu menulis ke variabel (katakanlah queueLength
), dan satu yang selalu membaca dari variabel yang sama.
Jika queueLength
tidak mudah menguap, utas A dapat menulis lima kali, tetapi utas B dapat melihat bahwa penulisan tersebut tertunda (atau bahkan berpotensi dalam urutan yang salah).
Sebuah solusi adalah mengunci, tetapi Anda juga bisa menggunakan volatile dalam situasi ini. Ini akan memastikan bahwa utas B akan selalu melihat hal terbaru yang ditulis oleh utas A. Namun perlu dicatat bahwa logika ini hanya berfungsi jika Anda memiliki penulis yang tidak pernah membaca, dan pembaca yang tidak pernah menulis, dan jika hal yang Anda tulis adalah nilai atom. Segera setelah Anda melakukan satu baca-modifikasi-tulis, Anda harus pergi ke operasi Saling Bertautan atau menggunakan Kunci.