Mengapa fork () telah dirancang untuk mengembalikan deskriptor file?


16

Pada nya halaman web tentang para trik self-pipa , Dan Bernstein menjelaskan kondisi ras dengan select()dan sinyal, menawarkan solusi dan menyimpulkan bahwa

Tentu saja, Hal yang Benar adalah fork()mengembalikan deskriptor file, bukan ID proses.

Apa yang dia maksudkan dengan ini - apakah ini sesuatu tentang kemampuan select()proses anak untuk menangani perubahan status mereka alih-alih harus menggunakan penangan sinyal untuk mendapat pemberitahuan tentang perubahan status itu?


Apakah artikel itu mendapat input dan output yang campur aduk, atau saya tidak membacanya dengan benar?
ctrl-alt-delor

Anda dapat meminta sinyal untuk dikirimkan melalui pipa. Itu yang saya lakukan.
ctrl-alt-delor

@ ctrl-alt-delor, yeah, dia tampaknya menggunakan "input / output pipa" agak aneh, tapi saya pikir itu jelas di mana dia menulis dan di mana membaca dari sebuah pipa. Teks itu dari tahun 2003, dan aku tidak yakin signalfddan itu adalah hal yang dulu?
ilkkachu

5
Dan tahu apa yang dia bicarakan, meskipun dia bisa sedikit provokatif. Jika saya sengaja provokatif, saya berpendapat bahwa Tentu saja, Hal yang Benar adalah untuk menyingkirkan SIGCHLD.
Steve Summit

1
@ Mosvy Saya sedikit melebih-lebihkan, tetapi setiap program dan setiap programmer yang pernah saya lihat yang telah mencoba menggunakan SIGCHLD memiliki masalah dengannya. Ini adalah kondisi lomba yang menunggu untuk terjadi. Kembali ketika semua yang kita miliki adalah memblokir wait(), ada hal-hal yang tidak dapat Anda lakukan, jadi seseorang menemukan SIGCHLD, tetapi itu adalah pekerjaan yang buruk. Dalam pengalaman saya, dan sekarang bahwa mereka ada, percikan bagus, nonblocking wait3(), wait4()dan / atau waitpid()panggilan di tempat-tempat kunci (mungkin Anda acara loop utama) adalah alternatif yang jauh lebih unggul.
Steve Summit

Jawaban:


14

Masalahnya dijelaskan di sana di sumber Anda, select()harus terganggu oleh sinyal seperti SIGCHLD, tetapi dalam beberapa kasus itu tidak berfungsi dengan baik. Jadi solusinya adalah memiliki sinyal menulis ke pipa, yang kemudian ditonton select(). Menonton deskriptor file adalah untuk apa select(), sehingga bisa mengatasi masalah.

Solusinya pada dasarnya mengubah acara sinyal menjadi acara deskriptor file. Jika fork()hanya mengembalikan fd di tempat pertama, solusi tidak akan diperlukan, karena fd itu kemudian dapat digunakan secara langsung select().

Jadi ya, uraian Anda pada paragraf terakhir sepertinya tepat bagi saya.


Alasan lain bahwa fd (atau jenis lain dari pegangan kernel) akan lebih baik daripada nomor proses id, adalah bahwa PID dapat digunakan kembali setelah proses mati. Itu bisa menjadi masalah dalam beberapa kasus ketika mengirim sinyal ke proses, mungkin tidak mungkin untuk mengetahui dengan pasti bahwa prosesnya adalah yang Anda pikirkan, dan bukan yang lain menggunakan kembali PID yang sama. (Meskipun saya pikir ini seharusnya tidak menjadi masalah ketika mengirim sinyal ke proses anak, karena orang tua harus menjalankan wait()pada anak untuk PID yang akan dirilis.)


Yang mengatakan, saya tidak ingat persis kasus yang saya baca tentang penggunaan kembali PID menjadi masalah, jadi jika ada yang ingin menguraikan atau mengklarifikasi itu, atau bahkan mengedit di atas, jangan ragu untuk melakukannya.
ilkkachu

2
Seperti yang sudah Anda nyatakan, tidak ada alasan untuk orang tua menemukan pid anak sendiri telah digunakan kembali. Ia memegang kendali penuh atas situasi itu karena dialah yang memanggil wait().
Joshua

Ini disebut proses zombie : "suatu proses yang telah menyelesaikan eksekusi tetapi masih memiliki entri dalam tabel proses: ini adalah proses dalam" Keadaan dihentikan ". Ini terjadi untuk proses anak, di mana entri masih diperlukan untuk memungkinkan orang tua proses membaca status keluar anaknya "
Lassi

6
Perlu disebutkan bahwa sekarang Linux dapat mengembalikan deskriptor file (pidfd) dari clone, yang merupakan panggilan sistem aktual yang dipanggil oleh garpu pada LInux. Bendera untuk mengaktifkan ini disebut CLONE_PIDFD- Lihat misalnya lwn.net/Articles/784831 .
KJ Tsanaktsidis

1
@ Lie Ryan, Re " Memiliki fork () mengembalikan pegangan global daripada pegangan lokal secara konseptual lebih benar karena ", Windows menggunakan pegangan proses. Kode pid dan keluar tetap ada sampai semua pegangan untuk proses ditutup (daripada menunggu orang tua untuk menuai), menghindari kondisi balapan yang umum dalam sistem unix. Ketika gagang menjaga proses tetap hidup, jauh lebih masuk akal bagi mereka untuk menjadi pegangan lokal daripada global.
ikegami

9

Itu hanya merenung di baris "akan lebih bagus jika Unix dirancang berbeda dari itu".

Masalah dengan PID adalah bahwa mereka hidup di ruang nama global tempat mereka dapat digunakan kembali untuk proses lain, dan alangkah baiknya jika fork()dikembalikan pada orang tua semacam pegangan yang akan dijamin untuk selalu merujuk pada proses anak, dan bahwa itu bisa lewat ke proses lain melalui warisan atau soket unix / SCM_RIGHTS[1].

Lihat juga diskusi di sini untuk upaya baru-baru ini untuk "memperbaikinya" di Linux, termasuk menambahkan bendera clone()yang akan menyebabkannya mengembalikan pid-fd bukan PID.

Tetapi meskipun begitu, itu tidak akan menghilangkan kebutuhan untuk hack pipa-diri [2] atau antarmuka yang lebih baik, karena sinyal yang memberitahukan proses induk tentang keadaan anak bukan satu-satunya yang ingin Anda tangani dalam loop utama dari program ini. Sayangnya, hal-hal seperti epoll(7) + signalfd(2)di Linux atau kqueue(2)BSD tidak standar - satu-satunya antarmuka standar (tetapi tidak didukung pada sistem yang lebih tua) adalah yang jauh lebih rendah pselect(2).

[1] Mencegah PID agar tidak didaur ulang pada saat waitpid()syscall telah kembali dan nilai kembalinya digunakan mungkin dapat dicapai pada sistem yang lebih baru dengan menggunakan waitid(.., WNOWAIT)sebagai gantinya.

[2] Saya tidak akan mengomentari klaim DJ Bernstein bahwa ia menciptakannya (maaf atas apofasis ;-)).


8

Bernstein tidak memberikan banyak konteks untuk pernyataan "Right Thing" ini, tetapi saya akan menebak: memiliki fork (2) mengembalikan PID tidak konsisten dengan open (2), creat (2) dll yang kembali deskriptor file. Sisanya dari sistem Unix bisa melakukan manipulasi proses dengan deskriptor file yang mewakili suatu proses, bukan PID. System call signalfd (2) ada, yang memungkinkan interaksi yang agak lebih baik antara sinyal dan deskriptor file, dan menunjukkan bahwa file-deskriptor yang mewakili suatu proses dapat bekerja.


signalfd (2) terlihat keren, terima kasih sudah menyebutkannya! Sayang sekali hanya Linux.
Lassi

1
Ada juga diskusi tentang pidfd_opendi Linux, lihat misalnya lwn.net/Articles/789023
dhag
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.