Saya ingin membuat kode program kecil yang secara visual menggambarkan perilaku volatile
kata kunci. Idealnya, ini harus menjadi program yang melakukan akses bersamaan ke bidang statis non volatile dan yang mendapat perilaku salah karenanya.
Menambahkan kata kunci yang mudah menguap dalam program yang sama akan menyelesaikan masalah.
Sesuatu yang tidak berhasil saya capai. Bahkan mencoba beberapa kali, mengaktifkan pengoptimalan, dll., Saya selalu mendapatkan perilaku yang benar tanpa kata kunci 'volatile'.
Apakah Anda tahu tentang topik ini? Apakah Anda tahu cara mensimulasikan masalah seperti itu dalam aplikasi demo sederhana? Apakah itu tergantung pada perangkat keras?
Ya, ini bergantung pada perangkat keras (Anda tidak mungkin melihat masalah tanpa banyak prosesor), tetapi juga bergantung pada implementasi. Spesifikasi model memori dalam spesifikasi CLR mengizinkan hal-hal yang tidak perlu dilakukan oleh implementasi Microsoft CLR.
sumber
Ini sebenarnya bukan masalah kesalahan yang terjadi ketika kata kunci 'volatile' tidak ditentukan, lebih dari itu kesalahan dapat terjadi jika belum ditentukan. Umumnya Anda akan tahu kapan kasus ini lebih baik daripada kompiler!
Cara termudah untuk memikirkannya adalah bahwa kompilator dapat, jika diinginkan, menyebariskan nilai-nilai tertentu. Dengan menandai nilai sebagai volatile, Anda memberi tahu diri Anda sendiri dan compiler bahwa nilainya mungkin benar-benar berubah (meskipun compiler tidak berpikir demikian). Ini berarti kompilator tidak boleh memasukkan nilai sebaris, menyimpan cache atau membaca nilai lebih awal (dalam upaya untuk mengoptimalkan).
Perilaku ini sebenarnya bukan kata kunci yang sama seperti di C ++.
MSDN memiliki penjelasan singkat di sini . Berikut adalah posting yang mungkin lebih mendalam tentang subjek Volatilitas, Atomicity, dan Interlocking
sumber
Sulit untuk mendemonstrasikan di C #, karena kode tersebut diabstraksi oleh mesin virtual, sehingga pada satu implementasi mesin ini bekerja dengan baik tanpa volatile, sementara itu mungkin gagal pada yang lain.
Wikipedia memiliki contoh bagus bagaimana mendemonstrasikannya dalam C.
Hal yang sama dapat terjadi di C # jika kompilator JIT memutuskan bahwa nilai variabel tidak dapat berubah dan dengan demikian membuat kode mesin yang bahkan tidak memeriksanya lagi. Jika sekarang utas lain mengubah nilainya, utas pertama Anda mungkin masih terjebak di dalam lingkaran.
Contoh lainnya adalah Busy Waiting.
Sekali lagi, ini bisa terjadi dengan C # juga, tetapi sangat tergantung pada mesin virtual dan kompiler JIT (atau interpreter, jika tidak memiliki JIT ... secara teori, saya pikir MS selalu menggunakan kompiler JIT dan juga penggunaan Mono satu; tetapi Anda mungkin dapat menonaktifkannya secara manual).
sumber
Inilah kontribusi saya untuk pemahaman kolektif tentang perilaku ini ... Ini tidak banyak, hanya demonstrasi (berdasarkan demo xkip) yang menunjukkan perilaku ayat yang mudah menguap nilai int non-volatile (yaitu "normal"), berdampingan -di samping, dalam program yang sama ... yang saya cari ketika saya menemukan utas ini.
using System; using System.Threading; namespace VolatileTest { class VolatileTest { private volatile int _volatileInt; public void Run() { new Thread(delegate() { Thread.Sleep(500); _volatileInt = 1; }).Start(); while ( _volatileInt != 1 ) ; // Do nothing Console.WriteLine("_volatileInt="+_volatileInt); } } class NormalTest { private int _normalInt; public void Run() { new Thread(delegate() { Thread.Sleep(500); _normalInt = 1; }).Start(); // NOTE: Program hangs here in Release mode only (not Debug mode). // See: http://stackoverflow.com/questions/133270/illustrating-usage-of-the-volatile-keyword-in-c-sharp // for an explanation of why. The short answer is because the // compiler optimisation caches _normalInt on a register, so // it never re-reads the value of the _normalInt variable, so // it never sees the modified value. Ergo: while ( true )!!!! while ( _normalInt != 1 ) ; // Do nothing Console.WriteLine("_normalInt="+_normalInt); } } class Program { static void Main() { #if DEBUG Console.WriteLine("You must run this program in Release mode to reproduce the problem!"); #endif new VolatileTest().Run(); Console.WriteLine("This program will now hang!"); new NormalTest().Run(); } } }
Ada beberapa penjelasan singkat yang sangat bagus di atas, serta beberapa referensi yang bagus. Terima kasih untuk semua yang telah membantu saya memahami
volatile
(setidaknya cukup untuk mengetahui tidak bergantung pada divolatile
mana insting pertama sayalock
).Salam, dan Terima kasih untuk SEMUA ikannya. Keith.
PS: saya akan sangat tertarik demo dari permintaan yang asli, yang adalah: "Saya ingin melihat sebuah static int volatil berperilaku dengan benar di mana sebuah static int bertingkah.
Saya telah mencoba dan gagal dalam tantangan ini. (Sebenarnya saya menyerah cukup cepat ;-). Dalam segala hal yang saya coba dengan vars statis, mereka berperilaku "benar" terlepas dari apakah mereka mudah berubah atau tidak ... dan saya ingin penjelasan MENGAPA demikian, jika memang demikian ... Apakah itu kompilator tidak menyimpan nilai dari static vars dalam register ( sebagai gantinya ia menyimpan referensi ke alamat heap itu)?
Tidak, ini bukan pertanyaan baru ... ini adalah upaya untuk mengarahkan komunitas kembali ke pertanyaan awal.
sumber
Saya menemukan teks berikut oleh Joe Albahari yang sangat membantu saya.
Saya mengambil contoh dari teks di atas yang saya ubah sedikit, dengan membuat bidang volatile statis. Saat Anda menghapus
volatile
kata kunci, program akan memblokir tanpa batas. Jalankan contoh ini dalam mode Rilis .class Program { public static volatile bool complete = false; private static void Main() { var t = new Thread(() => { bool toggle = false; while (!complete) toggle = !toggle; }); t.Start(); Thread.Sleep(1000); //let the other thread spin up complete = true; t.Join(); // Blocks indefinitely when you remove volatile } }
sumber