Sambil menunggu read()
atau write()
ke/dari pengembalian deskriptor file, proses akan ditempatkan dalam jenis tidur khusus, yang dikenal sebagai "D" atau "Disk Sleep". Ini istimewa, karena prosesnya tidak dapat dimatikan atau diinterupsi saat dalam keadaan seperti itu. Sebuah proses yang menunggu pengembalian dari ioctl() juga akan ditidurkan dengan cara ini.
Pengecualian untuk ini adalah ketika file (seperti terminal atau perangkat karakter lainnya) dibuka di O_NONBLOCK
mode, diteruskan ketika diasumsikan bahwa perangkat (seperti modem) akan membutuhkan waktu untuk melakukan inisialisasi. Namun, Anda menunjukkan perangkat pemblokiran dalam pertanyaan Anda. Juga, saya belum pernah mencoba ioctl()
yang kemungkinan akan memblokir fd yang dibuka dalam mode non-pemblokiran (setidaknya tanpa disadari).
Cara proses lain dipilih bergantung sepenuhnya pada penjadwal yang Anda gunakan, serta proses lain apa yang mungkin telah dilakukan untuk mengubah bobotnya dalam penjadwal tersebut.
Beberapa program ruang pengguna dalam keadaan tertentu telah diketahui tetap dalam keadaan ini selamanya, hingga dimulai ulang. Ini biasanya dikelompokkan dengan "zombie" lain, tetapi istilahnya tidak benar karena secara teknis tidak mati.
Proses yang melakukan I/O akan dimasukkan ke dalam status D (tidur tanpa gangguan) , yang membebaskan CPU hingga ada interupsi perangkat keras yang memberi tahu CPU untuk kembali menjalankan program. Lihat man ps
untuk status proses lainnya.
Bergantung pada kernel Anda, ada penjadwal proses , yang melacak runqueue proses yang siap dijalankan. Itu, bersama dengan algoritma penjadwalan, memberi tahu kernel proses mana yang akan ditetapkan ke CPU mana. Ada proses kernel dan proses pengguna untuk dipertimbangkan. Setiap proses dialokasikan irisan waktu, yang merupakan potongan waktu CPU yang diizinkan untuk digunakan. Setelah proses menggunakan semua irisan waktunya, proses tersebut ditandai sebagai kedaluwarsa dan diberi prioritas lebih rendah dalam algoritme penjadwalan.
Di kernel 2.6 , ada O(1) penjadwal kompleksitas waktu , jadi tidak peduli berapa banyak proses yang Anda jalankan, itu akan menetapkan CPU dalam waktu yang konstan. Ini lebih rumit, karena 2.6 memperkenalkan preemption dan penyeimbangan beban CPU bukanlah algoritme yang mudah. Bagaimanapun, ini efisien dan CPU tidak akan diam saat Anda menunggu I/O.
Ketika suatu proses perlu mengambil data dari disk, secara efektif berhenti berjalan pada CPU untuk membiarkan proses lain berjalan karena operasi mungkin membutuhkan waktu lama untuk diselesaikan – setidaknya 5 ms mencari waktu untuk disk adalah hal biasa, dan 5 ms adalah 10 juta Siklus CPU, keabadian dari sudut pandang program!
Dari sudut pandang pemrogram (juga disebut "di ruang pengguna"), ini disebut panggilan sistem pemblokiran . Jika Anda memanggil write(2)
(yang merupakan pembungkus libc tipis di sekitar panggilan sistem dengan nama yang sama), proses Anda tidak berhenti tepat di batas itu; itu berlanjut, di kernel, menjalankan kode panggilan sistem. Sebagian besar waktu itu sampai ke driver pengontrol disk tertentu (nama file → sistem file/VFS → perangkat blok → driver perangkat), di mana perintah untuk mengambil blok pada disk dikirimkan ke perangkat keras yang tepat, yang sangat operasi cepat sebagian besar waktu.
KEMUDIAN proses dimasukkan ke dalam kondisi tidur (di ruang kernel, pemblokiran disebut tidur – tidak ada yang pernah 'diblokir' dari sudut pandang kernel). Itu akan dibangunkan setelah perangkat keras akhirnya mengambil data yang tepat, kemudian prosesnya akan ditandai sebagai dapat dijalankan dan akan dijadwalkan. Akhirnya, penjadwal akan menjalankan proses.
Terakhir, di ruang pengguna, panggilan sistem pemblokiran kembali dengan status dan data yang sesuai, dan alur program terus berlanjut.
Sebagian besar panggilan sistem I/O dapat dipanggil dalam mode non-pemblokiran (lihat O_NONBLOCK
di open(2)
dan fcntl(2)
). Dalam hal ini, panggilan sistem segera kembali dan hanya melaporkan penyerahan operasi disk. Pemrogram harus secara eksplisit memeriksa di lain waktu apakah operasi selesai, berhasil atau tidak, dan mengambil hasilnya (misalnya, dengan select(2)
). Ini disebut pemrograman asinkron atau berbasis peristiwa.
Sebagian besar jawaban di sini menyebutkan status D (yang disebut TASK_UNINTERRUPTIBLE
dalam nama negara bagian Linux) salah. D state adalah mode tidur khusus yang hanya dipicu di jalur kode ruang kernel, ketika jalur kode itu tidak dapat diinterupsi (karena akan terlalu rumit untuk diprogram), dengan harapan akan memblokir hanya untuk waktu yang sangat singkat. Saya percaya bahwa sebagian besar "status D" sebenarnya tidak terlihat; umurnya sangat singkat dan tidak dapat diamati dengan alat pengambilan sampel seperti 'atas'.
Anda dapat menemukan proses yang tidak dapat dibunuh dalam keadaan D dalam beberapa situasi. NFS terkenal akan hal itu, dan saya telah menemukannya berkali-kali. Saya pikir ada bentrokan semantik antara beberapa jalur kode VFS, yang menganggap selalu mencapai disk lokal dan deteksi kesalahan cepat (pada SATA, batas waktu kesalahan sekitar 100 ms), dan NFS, yang sebenarnya mengambil data dari jaringan yang lebih tangguh dan pemulihannya lambat (biasanya TCP timeout 300 detik). Baca artikel ini untuk mengetahui solusi keren yang diperkenalkan di Linux 2.6.25 dengan TASK_KILLABLE
negara. Sebelum era ini ada peretasan di mana Anda sebenarnya dapat mengirim sinyal ke klien proses NFS dengan mengirimkan SIGKILL ke utas kernel rpciod
, tapi lupakan trik jelek itu.…