Mengapa garpu mekanisme pembuatan proses default?

46

Panggilan sistem UNIX untuk pembuatan proses, fork (), menciptakan proses anak dengan menyalin proses induk. Pemahaman saya adalah bahwa ini hampir selalu diikuti oleh panggilan ke exec () untuk mengganti ruang memori proses anak (termasuk segmen teks). Menyalin ruang memori orang tua dalam fork () selalu tampak boros bagi saya (meskipun saya menyadari pemborosan dapat diminimalkan dengan membuat segmen memori copy-on-write sehingga hanya pointer yang disalin). Lagi pula, apakah ada yang tahu mengapa pendekatan duplikasi ini diperlukan untuk proses pembuatan?

Ellen Spertus
sumber
3
Perhatikan bahwa fork(2)halaman manual di Linux mengatakan: Under Linux, fork() is implemented using copy-on-write pages, so the only penalty that it incurs is the time and memory required to duplicate the parent's page tables, and to create a unique task structure for the child. Saya membayangkan (tetapi tidak tahu pasti) bahwa ini adalah kasus untuk rasa Unix modern lainnya.
larsks
4
Yang asli, PDP-11 Unix benar-benar, benar-benar menyalin semua byte dari proses bercabang: tetapi hanya memiliki 64Kb executable, dan paling banyak 64Kb data, jadi itu bukan beban besar, bahkan pada tahun 1975. Saya akan tebak bahwa SETIAP unix dan unix-a-like sejak sekitar 1990 telah memiliki segmen teks copy-on-write, jadi saya bahkan tidak yakin mengapa buku dan artikel menyebarkan "masalah kinerja dengan garpu" lagi.
Bruce Ediger
Saat ini, garpu diimplementasikan dengan cara yang sama untuk vfork ( openbsd.org/cgi-bin/... ). Ini efisien, jangan khawatir.
Aki
Juga perhatikan bahwa ada banyak penggunaan di mana Anda tidak mengeksekusi setelah garpu (atau setidaknya, tidak exec segera): pikirkan pipa dan server web.
jfg956
Anda mungkin akan lambat. Tetapi seperti @cjm mengatakan lihat alternatif Microsoft menggunakan CreateProcess, mereka harus mengimplementasikan utas lebih awal (mungkin satu-satunya yang mereka pimpin), karena CreateProcess lambat. (Mereka juga membutuhkan utas karena selectputus, tapi itu cerita lain).
ctrl-alt-delor

Jawaban:

57

Ini untuk menyederhanakan antarmuka. Alternatif untuk forkdan execakan menjadi sesuatu seperti fungsi CreateProcess Windows . Perhatikan berapa banyak parameter yang CreateProcessdimiliki, dan banyak dari mereka adalah struct dengan lebih banyak parameter. Ini karena semua yang Anda mungkin ingin kontrol tentang proses baru harus diteruskan CreateProcess. Faktanya, CreateProcesstidak memiliki parameter yang cukup, jadi Microsoft harus menambahkan CreateProcessAsUser dan CreateProcessWithLogonW .

Dengan fork/execmodel, Anda tidak perlu semua parameter itu. Alih-alih, atribut tertentu dari proses dipertahankan di seluruh exec. Ini memungkinkan Anda untuk fork, kemudian mengubah atribut proses apa pun yang Anda inginkan (menggunakan fungsi yang sama seperti yang biasa Anda gunakan), lalu exec . Di Linux, forktidak memiliki parameter, dan execvehanya memiliki 3: program untuk dijalankan, baris perintah untuk memberikannya, dan lingkungannya. (Ada execfungsi - fungsi lain , tetapi mereka hanya pembungkus yang execvedisediakan oleh perpustakaan C untuk menyederhanakan kasus penggunaan umum.)

Jika Anda ingin memulai proses dengan direktori saat ini berbeda: fork, chdir, exec.

Jika Anda ingin mengarahkan ulang stdin / stdout:, forktutup / buka file exec,.

Jika Anda ingin pengguna beralih: fork, setuid, exec.

Semua hal ini dapat digabungkan sesuai kebutuhan. Jika seseorang menghasilkan atribut proses jenis baru, Anda tidak perlu mengubah forkdan exec.

Seperti yang disebutkan oleh larsks, sebagian besar Unix modern menggunakan copy-on-write, jadi forktidak melibatkan overhead yang signifikan.

cjm
sumber
16
Penjelasan yang bagus. "Mereka yang tidak mengerti UNIX dikutuk untuk menciptakannya kembali, dengan buruk." - Henry Spencer
Kyle Jones
1
Terima kasih! Apakah Anda punya referensi, kebetulan?
Ellen Spertus
1
@ Aki, tidak, CreateProcess () benar-benar membuat proses baru dan membangunnya dari awal, tanpa forking.
psusi
2
Tetapi haruskah tidak ada yang setara dengan CreateProcess () di suatu tempat di Unix? Kalau tidak, bagaimana proses pertama kali dibuat? Tidak seperti dewa pencipta mitologis, proses pertama tidak dapat memotong () dirinya dari ketiadaan. ;-)
Steven Monday
2
@ SevenMonday, ya, tapi itu dalam kode inisialisasi kernel dan tidak dapat diakses secara eksternal. Tidak perlu semua parameter itu karena hampir semuanya hardcoded. Itu hanya dapat membuat ID proses 1, alias proses init. Setelah itu, proses dibuat hanya dengan forking.
cjm
5

Sebagai tambahan untuk jawaban cjm, Spesifikasi Unix Tunggal mendefinisikan fungsi bernama vfork(). Fungsi itu bekerja seperti garpu, kecuali bahwa proses bercabang memiliki perilaku yang tidak terdefinisi jika melakukan apa pun selain mencoba memanggil fungsi keluarga eksekutif, atau memanggil _exit().

Jadi cukup banyak satu-satunya penggunaan dengan perilaku yang didefinisikan adalah:

pid_t ret = vfork();
if(ret == 0)
{
    exec(...);
    _exit(EXIT_FAILURE); //in case exec failed for any reason.
}

Jadi apa fungsinya vfork? Itu murah fork. Dalam implementasi tanpa copy-on-write, proses yang dihasilkan akan berbagi ruang memori dengan proses asli (karenanya perilaku yang tidak terdefinisi). Dalam implementasi dengan copy-on-write, vforkdiizinkan untuk identik dengan fork(), karena implementasi copy-on-write cepat.

Ada juga posix_spawnfungsi opsional (dan posix_spawnpfungsi) yang langsung dapat membuat proses baru. (Ini juga diperbolehkan untuk mengimplementasikannya dengan panggilan pustaka menggunakan forkdan exec, dan contoh implementasi disediakan.)

Kevin Cathcart
sumber