Pemrogram C sering mengambil volatile yang berarti bahwa variabel dapat diubah di luar utas eksekusi saat ini; akibatnya, mereka kadang-kadang tergoda untuk menggunakannya dalam kode kernel ketika struktur data bersama digunakan. Dengan kata lain, mereka telah dikenal untuk memperlakukan tipe volatil sebagai semacam variabel atom mudah, yang bukan mereka. Penggunaan volatile dalam kode kernel hampir tidak pernah benar; dokumen ini menjelaskan alasannya.
Poin kunci untuk memahami sehubungan dengan volatile adalah bahwa tujuannya adalah untuk menekan optimasi, yang hampir tidak pernah benar-benar ingin dilakukan. Dalam kernel, seseorang harus melindungi struktur data bersama dari akses bersamaan yang tidak diinginkan, yang merupakan tugas yang sangat berbeda. Proses melindungi terhadap konkurensi yang tidak diinginkan juga akan menghindari hampir semua masalah terkait optimasi dengan cara yang lebih efisien.
Seperti volatile, kernel primitif yang membuat akses bersamaan ke data yang aman (spinlocks, mutexes, hambatan memori, dll.) Dirancang untuk mencegah optimasi yang tidak diinginkan. Jika mereka digunakan dengan benar, tidak perlu menggunakan volatile juga. Jika volatile masih diperlukan, hampir pasti ada bug dalam kode di suatu tempat. Dalam kode kernel yang ditulis dengan benar, volatile hanya dapat berfungsi untuk memperlambat segalanya.
Pertimbangkan blok khas dari kode kernel:
spin_lock(&the_lock);
do_something_on(&shared_data);
do_something_else_with(&shared_data);
spin_unlock(&the_lock);
Jika semua kode mengikuti aturan penguncian, nilai shared_data tidak dapat berubah secara tak terduga saat the_lock dipegang. Kode lain yang mungkin ingin dimainkan dengan data itu akan menunggu di kunci. Primitif spinlock bertindak sebagai penghalang memori - mereka secara eksplisit ditulis untuk melakukannya - yang berarti bahwa akses data tidak akan dioptimalkan melintasi mereka. Jadi kompiler mungkin berpikir ia tahu apa yang akan ada di shared_data, tetapi panggilan spin_lock (), karena bertindak sebagai penghalang memori, akan memaksanya untuk melupakan apa pun yang ia ketahui. Tidak akan ada masalah optimasi dengan akses ke data itu.
Jika shared_data dinyatakan tidak stabil, penguncian akan tetap diperlukan. Tetapi kompiler juga akan dicegah mengoptimalkan akses ke shared_data dalam bagian kritis, ketika kita tahu bahwa tidak ada orang lain yang dapat bekerja dengannya. Saat kunci ditahan, shared_data tidak mudah menguap. Saat berhadapan dengan data bersama, penguncian yang tepat membuat volatil tidak perlu - dan berpotensi berbahaya.
Kelas penyimpanan yang mudah menguap awalnya dimaksudkan untuk register I / O yang dipetakan oleh memori. Di dalam kernel, register akses juga harus dilindungi oleh kunci, tetapi seseorang juga tidak ingin kompiler "mengoptimalkan" register mengakses dalam bagian kritis. Tetapi, di dalam kernel, akses memori I / O selalu dilakukan melalui fungsi accessor; mengakses memori I / O secara langsung melalui pointer tidak disukai dan tidak berfungsi pada semua arsitektur. Aksesor tersebut ditulis untuk mencegah optimasi yang tidak diinginkan, jadi, sekali lagi, volatile tidak diperlukan.
Situasi lain di mana orang mungkin tergoda untuk menggunakan volatile adalah ketika prosesor sedang sibuk menunggu nilai variabel. Cara yang tepat untuk melakukan penantian yang sibuk adalah:
while (my_variable != what_i_want)
cpu_relax();
Panggilan cpu_relax () dapat menurunkan konsumsi daya CPU atau menghasilkan prosesor kembar yang mengalami hipertensi; kebetulan juga berfungsi sebagai penghalang memori, jadi, sekali lagi, volatile tidak perlu. Tentu saja, penantian yang sibuk biasanya merupakan tindakan anti-sosial untuk memulai.
Masih ada beberapa situasi langka di mana volatile masuk akal di kernel:
Fungsi-fungsi accessor yang disebutkan di atas mungkin menggunakan volatile pada arsitektur di mana akses memori I / O langsung berfungsi. Pada dasarnya, setiap panggilan accessor menjadi bagian penting sendiri dan memastikan bahwa akses terjadi seperti yang diharapkan oleh programmer.
Kode perakitan sebaris yang mengubah memori, tetapi yang tidak memiliki efek samping lain yang terlihat, berisiko dihapus oleh GCC. Menambahkan kata kunci yang mudah menguap ke pernyataan asm akan mencegah penghapusan ini.
Variabel jiffies spesial karena dapat memiliki nilai yang berbeda setiap kali direferensikan, tetapi dapat dibaca tanpa penguncian khusus. Jadi jiffies bisa berubah-ubah, tetapi penambahan variabel lain dari tipe ini sangat disukai. Jiffies dianggap sebagai masalah "warisan bodoh" (kata-kata Linus) dalam hal ini; memperbaiki itu akan lebih banyak masalah daripada nilainya.
Pointer ke struktur data dalam memori yang koheren yang dapat dimodifikasi oleh perangkat I / O, kadang-kadang, dapat berubah-ubah. Sebuah buffer cincin yang digunakan oleh adaptor jaringan, di mana adaptor itu mengubah pointer untuk menunjukkan deskriptor mana yang telah diproses, adalah contoh dari jenis situasi ini.
Untuk sebagian besar kode, tidak ada justifikasi di atas untuk volatile yang berlaku. Akibatnya, penggunaan volatile cenderung dilihat sebagai bug dan akan membawa pemeriksaan tambahan ke kode. Pengembang yang tergoda untuk menggunakan volatile harus mengambil langkah mundur dan berpikir tentang apa yang sebenarnya mereka coba capai.