Rumah >Tutorial sistem >LINUX >Master mengajar anda cara menyediakan tidur dan bangun proses Linux
Pengenalan | Di Linux, proses yang hanya menunggu masa CPU dipanggil proses sedia Ia diletakkan dalam baris gilir larian, dan bendera status proses sedia ialah TASK_RUNNING. Setelah potongan masa proses berjalan habis, penjadual kernel Linux akan melucutkan proses kawalan CPU dan memilih proses yang sesuai daripada baris gilir larian untuk dijalankan. |
Sudah tentu, proses juga boleh melepaskan kawalan CPU secara aktif. Jadual fungsi() ialah fungsi penjadualan yang boleh dipanggil secara aktif oleh proses untuk menjadualkan proses lain untuk menduduki CPU. Sebaik sahaja proses yang secara sukarela menyerahkan CPU dijadualkan semula untuk menduduki CPU, ia akan memulakan pelaksanaan dari tempat terakhir ia berhenti, iaitu, ia akan memulakan pelaksanaan dari baris kod seterusnya yang memanggil jadual ().
Kadangkala, proses perlu menunggu sehingga peristiwa tertentu berlaku, seperti pemulaan peranti, penyiapan operasi I/O atau tamat tempoh pemasa. Dalam kes ini, proses mesti dialih keluar daripada baris gilir larian dan ditambah pada baris gilir menunggu Pada masa ini, proses memasuki keadaan tidur.
Salah satunya ialah keadaan tidur terganggu, bendera statusnya ialah TASK_INTERRUPTIBLE
Satu lagi ialah keadaan tidur yang tidak terganggu dan bendera statusnya ialah TASK_UNINTERRUPTIBLE. Proses dalam keadaan tidur terganggu akan tidur sehingga keadaan tertentu menjadi benar Contohnya, menjana gangguan perkakasan, melepaskan sumber sistem yang sedang menunggu proses, atau menghantar isyarat boleh menjadi syarat untuk membangunkan proses. Keadaan tidur tidak terganggu adalah serupa dengan keadaan tidur terganggu, tetapi ia mempunyai satu pengecualian, iaitu, proses yang menyampaikan isyarat kepada keadaan tidur ini tidak boleh mengubah keadaannya, iaitu, ia tidak bertindak balas kepada isyarat untuk bangun. Keadaan tidur tidak terganggu biasanya kurang digunakan, tetapi ia masih sangat berguna dalam beberapa situasi tertentu Contohnya, proses mesti menunggu dan tidak boleh diganggu sehingga peristiwa tertentu berlaku.
Dalam sistem pengendalian Linux moden, proses biasanya memasuki keadaan tidur dengan memanggil jadual(). Kod berikut berfungsi
menunjukkan cara untuk meletakkan proses berjalan untuk tidur.
sleeping_task = semasa;
tetapkan_keadaan_semasa(TUGAS_GANGGU);
jadual();
func1();
/* Selebihnya kod ... */
Dalam pernyataan pertama, atur cara menyimpan penuding struktur proses sleeping_task, dan semasa ialah makro yang menunjuk kepada pelaksanaan semasa
struktur proses. set_current_state() menukar keadaan proses daripada keadaan pelaksanaan TASK_RUNNING kepada keadaan tidur
TASK_INTERRUPTIBLE. Jika schedule() dijadualkan oleh proses dalam keadaan TASK_RUNNING, maka schedule() akan menjadualkan proses lain untuk menduduki CPU jika schedule() dijadualkan oleh proses dalam keadaan TASK_INTERRUPTIBLE atau TASK_UNINTERRUPTIBLE, maka terdapat langkah tambahan untuk; Sedang dilaksanakan: Proses yang sedang dilaksanakan akan dialih keluar daripada baris gilir larian sebelum proses lain dijadualkan, yang akan menyebabkan proses larian tertidur kerana ia tidak lagi dalam baris gilir larian.
Kita boleh menggunakan fungsi berikut untuk membangunkan proses yang baru sahaja tidur.
proses_bangun(tugas_tidur);
Selepas memanggil wake_up_process(), status proses tidur akan ditetapkan kepada TASK_RUNNING dan penjadual
Ia akan ditambahkan pada baris gilir larian. Sudah tentu, proses ini hanya boleh digunakan pada kali berikutnya ia dijadualkan oleh penjadual.
Dalam hampir semua kes, proses akan tidur selepas memeriksa syarat-syarat tertentu dan mendapati syarat-syarat itu tidak dipenuhi. Tapi kadang-kadang
Walau bagaimanapun, proses akan mula tidur selepas syarat penghakiman adalah benar. Jika ini berlaku, proses itu akan tidur selama-lamanya. Dalam sistem pengendalian, apabila berbilang proses cuba melakukan beberapa pemprosesan pada data yang dikongsi, dan hasil akhir bergantung pada susunan proses dijalankan, keadaan perlumbaan berlaku. Ini adalah masalah biasa dalam sistem pengendalian. sehingga Ia adalah disebabkan oleh keadaan persaingan.
Bayangkan terdapat dua proses A dan B. Proses A sedang memproses senarai terpaut Ia perlu menyemak sama ada senarai terpaut itu kosong, ia akan memadamkan pautan
Data dalam jadual sedang menjalani beberapa operasi, dan proses B juga menambah nod pada senarai terpaut. Apabila senarai terpaut kosong, kerana tiada data untuk beroperasi, proses A menjadi tidur Apabila proses B menambah nod pada senarai terpaut, ia membangunkan proses A. Kodnya adalah seperti berikut:
.
Satu proses:
1 spin_lock(&list_lock);
2 jika(senarai_kosong(&senarai_kepala)) {
3 spin_unlock(&list_lock);
4 set_keadaan_semasa(TUGAS_GANGGU);
5 jadual();
6 spin_lock(&list_lock);
7}
8
9 /* Selebihnya kod ... */
10 spin_unlock(&list_lock);
Proses B:
100 spin_lock(&list_lock);
101 list_add_tail(&list_head, new_node);
102 spin_unlock(&list_lock);
103 proses_bangun(tugas_proses);
Akan ada masalah di sini Jika proses A dilaksanakan selepas baris 3 dan sebelum baris 4, proses B dijadualkan oleh pemproses lain
Dilaksanakan. Dalam kepingan masa ini, proses B telah menyelesaikan semua arahannya, jadi ia cuba membangunkan proses A. Pada masa ini, proses A masih belum memasuki tidur, jadi operasi bangun adalah tidak sah. Selepas ini, proses A terus dilaksanakan Ia akan tersalah anggap bahawa senarai terpaut masih kosong pada masa ini, jadi ia menetapkan statusnya kepada TASK_INTERRUPTIBLE dan kemudian memanggil schedule() untuk tidur. Memandangkan proses B terlepas untuk bangun, ia akan tidur selama-lamanya Ini adalah masalah bangun tidur tidak sah, kerana walaupun terdapat data dalam senarai terpaut yang perlu diproses, proses A masih tidur.
Sebelum keadaan, wake_up_process() proses B pada asalnya memberi peluang untuk menetapkan keadaan proses A kepada TASK_RUNNING Malangnya, keadaan proses A masih TASK_RUNNING pada masa ini, jadi wake_up_process() menukar keadaan proses A daripada tidur. negeri kepada keadaan berjalan. Untuk menyelesaikan masalah ini, mekanisme jaminan mesti digunakan untuk membuat penentuan bahawa senarai terpaut kosong dan menetapkan keadaan proses kepada keadaan tidur menjadi langkah penting, iaitu, punca keadaan perlumbaan mesti dihapuskan, supaya proses bangun ( ) boleh memainkan peranan untuk membangunkan proses yang dalam keadaan tidur.
Selepas mencari sebab, reka bentuk semula struktur kod proses A untuk mengelakkan masalah bangun tidur yang tidak sah dalam contoh di atas.
Satu proses:
1 set_keadaan_semasa(TUGAS_GANGGU);
2 spin_lock(&list_lock);
3 jika(senarai_kosong(&senarai_kepala)) {
4 spin_unlock(&list_lock);
5 jadual();
6 spin_lock(&list_lock);
7}
8 set_keadaan_semasa(TUGASAN_JALANKAN);
9
10 /* Selebihnya kod ... */
11 spin_unlock(&list_lock);
Seperti yang anda lihat, kod ini menetapkan keadaan proses pelaksanaan semasa kepada TASK_INTERRUPTIBLE sebelum menguji syarat dan menetapkan sendiri kepada keadaan TASK_RUNNING apabila senarai terpaut tidak kosong. Dengan cara ini, jika proses B dalam proses A, proses semak
Selepas memanggil wake_up_process() selepas senarai terpaut kosong, status proses A akan berubah secara automatik daripada TASK_INTERRUPTIBLE
asal
Ia menjadi TASK_RUNNING Selepas itu, walaupun proses memanggil schedule() sekali lagi, kerana status semasanya ialah TASK_RUNNING, ia masih tidak akan dialih keluar daripada baris gilir larian, jadi ia tidak akan memasuki tidur secara tidak sengaja, dan sudah tentu, masalahnya. bangun tidur yang tidak sah akan dielakkan.
Contoh kernel Linux
Dalam sistem pengendalian Linux, kestabilan kernel adalah penting Untuk mengelakkan masalah bangun tidak sah dalam kernel sistem pengendalian Linux,
Kernel Linux harus menggunakan operasi yang serupa dengan yang berikut apabila ia memerlukan proses tidur:
/* ‘q’ ialah barisan menunggu yang kita mahu tidur di */
DECLARE_WAITQUEUE(tunggu,semasa);
add_wait_queue(q, &wait);
tetapkan_keadaan_semasa(TUGAS_GANGGU);
/* atau TASK_INTERRUPTIBLE */
manakala(!condition) /* ‘condition’ ialah syarat menunggu*/
jadual();
set_keadaan_semasa(TUGASAN_JALANKAN);
remove_wait_queue(q, &wait);
Operasi di atas membolehkan proses menambah sendiri dengan selamat pada baris gilir menunggu untuk tidur melalui siri langkah berikut: Laraskan dahulu
Gunakan DECLARE_WAITQUEUE () untuk mencipta item baris gilir menunggu, kemudian panggil add_wait_queue() untuk menambah diri anda pada baris gilir menunggu dan tetapkan status proses kepada TASK_INTERRUPTIBLE atau TASK_INTERRUPTIBLE. Kemudian gelung menyemak sama ada keadaan itu benar: jika ya, tidak perlu tidur, jika syarat itu tidak benar, schedule() dipanggil. Apabila syarat yang disemak oleh proses dipenuhi, proses menetapkan sendiri kepada TASK_RUNNING dan memanggil remove_wait_queue() untuk mengalih keluar dirinya daripada baris gilir menunggu.
Seperti yang anda boleh lihat daripada di atas, penyelenggara kod kernel Linux juga menetapkan keadaan proses kepada keadaan tidur sebelum proses menyemak syarat,
Kemudian gelung menyemak keadaan. Jika syarat telah dipenuhi sebelum proses mula tidur, maka gelung akan keluar dan menggunakan set_current_state() untuk menetapkan keadaannya kepada sedia Ini juga memastikan bahawa proses tidak akan mempunyai kecenderungan untuk memasuki tidur secara tidak sengaja, dan sudah tentu ia tidak akan menyebabkan ralat masalah bangun tidak sah.
Mari kita gunakan contoh dalam kernel Linux untuk melihat cara kernel Linux mengelakkan tidur tidak sah Kod ini berasal dari kernel Linux2.6 (linux-2.6.11/kernel/sched.c: 4254):
.
4253 /* Tunggu kthread_stop */
4254 set_keadaan_semasa(TUGAS_GANGGU);
4255 manakala (!kthread_should_stop()) {
4256 jadual();
4257 set_keadaan_semasa(TUGAS_GANGGU);
4258 }
4259 __set_keadaan_semasa(TUGASAN_JALANKAN);
4260 pulangkan 0;
Kod di atas tergolong dalam utas perkhidmatan migrasi migration_thread ini sentiasa menyemak kthread_should_stop(),
Ia tidak boleh keluar dari gelung sehingga kthread_should_stop() mengembalikan 1, yang bermaksud bahawa proses akan tidur selagi kthread_should_stop() mengembalikan 0. Kita boleh melihat daripada kod bahawa semak kthread_should_stop() memang dilaksanakan selepas status proses ditetapkan kepada TASK_INTERRUPTIBLE. Oleh itu, jika proses lain cuba membangunkannya selepas pemeriksaan keadaan tetapi sebelum jadual(), operasi bangun proses itu tidak akan menjadi tidak sah.
Melalui perbincangan di atas, kita dapati bahawa kunci untuk mengelakkan proses bangun yang tidak sah dalam Linux adalah untuk membangunkan proses sebelum proses menyemak keadaan
Status ditetapkan kepada TASK_INTERRUPTIBLE atau TASK_UNINTERRUPTIBLE, dan jika syarat yang disemak dipenuhi, ia sepatutnya
Tetapkan semula statusnya kepada TASK_RUNNING. Dengan cara ini, tidak kira sama ada syarat menunggu proses itu dipenuhi atau tidak, proses itu tidak akan memasuki keadaan tidur secara tidak sengaja kerana ia dikeluarkan daripada baris gilir sedia, sekali gus mengelakkan masalah bangun tidur yang tidak sah.
Atas ialah kandungan terperinci Master mengajar anda cara menyediakan tidur dan bangun proses Linux. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!