Inti Linux ialah sistem kompleks yang perlu menangani pelbagai isu konkurensi, seperti penjadualan proses, pengurusan memori, pemacu peranti, protokol rangkaian, dsb. Untuk memastikan ketekalan dan ketepatan data, kernel Linux menyediakan pelbagai mekanisme penyegerakan, seperti kunci putaran, semafor, kunci baca-tulis, dsb. Walau bagaimanapun, mekanisme penyegerakan ini mempunyai beberapa kelemahan, seperti:
Jadi, adakah mekanisme penyegerakan yang lebih baik? Jawapannya ya, iaitu RCU (Read Copy Update). RCU ialah mekanisme penyegerakan berdasarkan model publish-subscribe, yang boleh mencapai operasi baca yang cekap dan operasi kemas kini latency rendah. Idea asas RCU adalah ini:
Apakah kelebihan RCU? Ia mempunyai ciri-ciri berikut:
Jadi, bagaimana RCU berfungsi? Apakah senario aplikasi yang ada padanya? Artikel ini akan memperkenalkan mekanisme penyegerakan RCU yang cekap dari dua aspek: prinsip dan aplikasi. Idea reka bentuk RCU agak jelas, dan perlindungan perkongsian tanpa kunci dicapai dengan menggantikan penunjuk lama dan baharu. Tetapi apabila ia datang kepada tahap kod, ia masih agak sukar untuk difahami. Dalam Bab 4 "Mekanisme Kernel Pemacu Peranti Linux Mendalam", peraturan yang diikuti di belakang RCU telah diterangkan dengan sangat jelas Peraturan ini dilihat dari perspektif yang agak tinggi, kerana saya fikir terlalu banyak analisis kod adalah mudah Biarkan pembaca tersesat dalam butiran. Selepas saya mendapat buku itu baru-baru ini, saya membaca dengan teliti teks di bahagian RCU sekali lagi, dan merasakan bahawa saya perlu menambah sedikit lagi kandungan, kerana beberapa perkara mungkin tidak sesuai untuk ditulis dalam buku itu.
Tanda bahawa bahagian bacaan RCU memasuki bahagian kritikal ialah memanggil rcu_read_lock Kod fungsi ini ialah:
1. 2. static inline void rcu_read_lock(void) 3. { 4. __rcu_read_lock(); 5. __acquire(RCU); 6. rcu_read_acquire(); 7. }
Nampaknya terdapat tiga panggilan fungsi dalam pelaksanaan ini, tetapi kerja sebenar dilakukan oleh fungsi pertama __rcu_read_lock() __rcu_read_lock() mematikan kebolehgunaan kernel dengan memanggil preempt_disable(). Tetapi gangguan dibenarkan. Anggapkan bahawa pembaca berada di bahagian kritikal rcu dan baru sahaja membaca penunjuk p dalam kawasan data yang dikongsi (tetapi belum lagi mengakses ahli data dalam p Satu gangguan berlaku, dan contoh pengendalian gangguan The ISR kebetulan perlu mengubah suai kawasan data yang ditunjukkan oleh p Menurut prinsip reka bentuk RCU, ISR akan memperuntukkan kawasan data baru_p dengan saiz yang sama, dan kemudian menyalin data dalam kawasan data lama p kepada yang baharu. kawasan data, dan kemudian dalam new_p Pada asasnya lakukan kerja pengubahsuaian data (kerana ia diubah suai dalam ruang new_p, tiada akses serentak ke p, jadi RCU adalah mekanisme bebas kunci, dan inilah sebabnya), selepas ISR menyelesaikan kerja kemas kini data , tetapkan new_p kepada p (p=new_p), dan akhirnya ia akan mendaftarkan fungsi panggil balik untuk melepaskan penunjuk p lama pada masa yang sesuai. Oleh itu, selagi semua rujukan kepada penunjuk lama p telah selesai, tiada masalah untuk mengeluarkan p. Apabila rutin pemprosesan gangguan menyelesaikan tugas-tugas ini dan kembali, proses yang terganggu masih akan mengakses data dalam ruang p, iaitu, data lama ini dibenarkan oleh mekanisme RCU. Peraturan RCU membenarkan ketidakkonsistenan paparan sumber sementara yang disebabkan oleh penukaran penunjuk antara pembaca dan penulis.
Persoalan menarik seterusnya mengenai RCU ialah: bila penunjuk lama boleh dikeluarkan. Jawapan untuk perkara ini yang saya lihat dalam banyak buku ialah: apabila suis proses berlaku pada semua pemproses dalam sistem. Jawapan bergaya ini sering mengelirukan pembaca yang baru menggunakan mekanisme RCU Mengapa kita perlu menunggu suis proses berlaku pada semua pemproses sebelum memanggil fungsi panggil balik untuk melepaskan penunjuk lama? Ini sebenarnya ditentukan oleh peraturan reka bentuk RCU: Semua rujukan kepada penunjuk lama hanya boleh berlaku dalam bahagian kritikal yang disertakan dalam rcu_read_lock dan rcu_read_unlock, dan penukaran proses tidak boleh dilakukan dalam bahagian kritikal ini , Setelah bahagian kritikal tidak sepatutnya lagi mempunyai sebarang bentuk rujukan kepada penunjuk lama p. Jelas sekali, peraturan ini memerlukan pembaca tidak boleh menukar proses dalam bahagian kritikal, kerana apabila terdapat suis proses, fungsi panggil balik yang melepaskan penuding lama boleh dipanggil, menyebabkan penuding lama dilepaskan Apabila proses beralih Apabila ia dijadualkan semula, ia mungkin merujuk ruang memori yang dibebaskan.
Sekarang kita lihat mengapa rcu_read_lock hanya perlu mematikan kebolehgunaan kernel, kerana ia menjadikannya mustahil untuk proses semasa ditukar dan dialih keluar walaupun gangguan berlaku di bahagian kritikal. Pembangun kernel, atau lebih tepatnya pereka RCU, hanya boleh berbuat begitu banyak. Langkah seterusnya adalah tanggungjawab pengguna Jika fungsi dipanggil dalam bahagian kritikal RCU, fungsi itu mungkin tidur, maka peraturan reka bentuk RCU akan dilanggar dan sistem akan memasuki keadaan tidak stabil.
Ini sekali lagi menunjukkan bahawa jika anda ingin menggunakan sesuatu, anda mesti memahami mekanisme dalamannya seperti contoh yang baru disebutkan di atas, walaupun tiada masalah dengan program sekarang, bahaya tersembunyi yang tinggal dalam sistem adalah seperti bom jangka. , yang mungkin berlaku pada bila-bila masa Diletupkan, terutamanya jika ia mengambil masa yang lama sebelum masalah itu tiba-tiba berlaku. Dalam kebanyakan kes, masa yang diperlukan untuk mencari masalah mungkin lebih lama daripada yang diperlukan untuk bertenang dan memahami dengan teliti prinsip RCU.
Pembaca di RCU mempunyai tahap kebebasan yang lebih tinggi daripada pembaca di rwlock. Oleh kerana pembaca RCU tidak perlu mempertimbangkan perasaan penulis apabila mengakses sumber yang dikongsi, ini berbeza dengan penulis rwlock. Pembaca rwlock perlu memastikan bahawa tiada penulis yang mengendalikan sumber semasa membaca sumber yang dikongsi. Perbezaan antara kedua-duanya adalah daripada pemisahan sumber perkongsian RCU antara pembaca dan penulis, manakala pembaca dan penulis rwlock hanya menggunakan satu salinan sumber yang dikongsi dari awal hingga akhir. Ini juga bermakna bahawa penulis dalam RCU perlu memikul lebih banyak tanggungjawab, dan beberapa jenis mekanisme pengecualian bersama mesti diperkenalkan antara berbilang penulis yang mengemas kini sumber kongsi yang sama, jadi RCU ialah "mekanisme bebas kunci" Kenyataan ini terhad kepada pembaca dan penulis. Oleh itu, kita melihat bahawa mekanisme RCU harus digunakan dalam situasi di mana terdapat sejumlah besar operasi baca dan operasi kemas kini yang agak sedikit. Pada masa ini, RCU boleh meningkatkan prestasi sistem, kerana operasi baca RCU hampir tidak mempunyai overhed kunci berbanding beberapa mekanisme penguncian yang lain.
Dalam penggunaan sebenar, sumber dikongsi selalunya wujud dalam bentuk senarai terpaut Kernel melaksanakan beberapa fungsi antara muka untuk operasi senarai terpaut dalam mod RCU Pembaca dan pengguna harus menggunakan fungsi kernel ini, seperti list_add_tail_rcu, list_add_rcu, hlist_replace_rcu, dsb. untuk penggunaan khusus, sila rujuk beberapa pengaturcaraan kernel atau maklumat pemacu peranti.Dari segi mengeluarkan penunjuk lama, kernel Linux menyediakan dua kaedah untuk digunakan oleh pengguna, satu ialah memanggil call_rcu, dan satu lagi adalah memanggil synchronize_rcu. Yang pertama ialah kaedah asynchronous call_rcu akan meletakkan fungsi panggil balik yang melepaskan penuding lama ke dalam nod, dan kemudian menambah nod ke senarai terpaut setempat bagi pemproses yang sedang menjalankan call_rcu Dalam bahagian softirq gangguan jam (RCU_SOFTIRQ ). , fungsi pemprosesan gangguan lembut rcu rcu_process_callbacks akan menyemak sama ada pemproses semasa telah mengalami tempoh tidur (senyap, yang melibatkan penjadualan proses kernel dan aspek lain Pelaksanaan kod kernel rcu menentukan bahawa semua pemproses dalam sistem telah mengalami Selepas tidur). tempoh (bermaksud suis proses telah berlaku pada semua pemproses, jadi penunjuk lama boleh dikeluarkan dengan selamat pada masa ini), fungsi panggil balik yang disediakan oleh call_rcu akan dipanggil.
Pelaksanaan synchronize_rcu menggunakan baris gilir menunggu Semasa pelaksanaannya, ia juga menambah nod pada senarai terpaut tempatan pemproses semasa seperti call_rcu Perbezaan daripada call_rcu ialah fungsi panggil balik dalam nod ini ialah wakeme_after_rcu, dan kemudian synchronize_rcu. akan tidur dalam baris gilir menunggu sehingga suis proses berlaku pada semua pemproses dalam sistem, jadi wakeme_after_rcu dipanggil oleh rcu_process_callbacks untuk membangunkan synchronize_rcu yang sedang tidur Selepas dikejutkan, synchronize_rcu tahu bahawa ia kini boleh melepaskan penunjuk lama.
Artikel ini memperkenalkan RCU, mekanisme penyegerakan yang cekap dalam kernel Linux Ia adalah mekanisme penyegerakan berdasarkan model publish-subscribe. Kami menganalisis idea asas, antara muka utama dan butiran pelaksanaan RCU dari aspek prinsip, dan memberikan contoh kod yang sepadan. Kami juga memperkenalkan penggunaan RCU dalam operasi senarai terpaut, pengurusan pemasa, pemprosesan gangguan lembut dan senario lain dari perspektif aplikasi, dan memberikan contoh kod yang sepadan. Dengan mempelajari artikel ini, kami boleh menguasai penggunaan asas RCU, dan dapat menggunakan RCU secara fleksibel dalam pembangunan sebenar untuk mencapai keperluan penyegerakan yang cekap. Semoga artikel ini dapat membantu anda!
Atas ialah kandungan terperinci Penjelasan terperinci tentang mekanisme RCU dalam kernel Linux. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!