GNU/Linux >> Belajar Linux >  >> Linux

Mengapa vfork() dimaksudkan untuk digunakan ketika proses anak memanggil exec() atau exit() segera setelah pembuatan?

Saat proses anak dibuat oleh vfork() memanggil exec() , bukan exec() memodifikasi ruang alamat dari proses induk, dengan memuat program baru?

Tidak, exec() menyediakan ruang alamat baru untuk program baru; itu tidak mengubah ruang alamat induk. Lihat misalnya pembahasan tentang exec fungsi di POSIX, dan execve() Linux halaman manual.

Ketika proses anak yang dibuat oleh vfork() memanggil exit(), apakah exit() tidak mengubah ruang alamat proses induk saat menghentikan anak?

exit() biasa mungkin – menjalankan kait keluar yang diinstal oleh program yang sedang berjalan (termasuk pustakanya). vfork() lebih membatasi; jadi, di Linux, ini mengamanatkan penggunaan _exit() yang tidak panggil fungsi pembersihan pustaka C.

vfork() ternyata cukup sulit untuk melakukannya dengan benar; itu telah dihapus dalam versi standar POSIX saat ini, dan posix_spawn() harus digunakan sebagai gantinya.

Namun, kecuali Anda benar-benar tahu apa yang Anda lakukan, sebaiknya Anda tidak gunakan vfork() atau posix_spawn(); tetap berpegang pada fork() lama yang bagus dan exec() .

Halaman manual Linux yang ditautkan di atas memberikan lebih banyak konteks:

Namun, di masa lalu yang buruk, fork(2) akan membutuhkan salinan lengkap dari ruang data penelepon, sering kali tidak perlu, karena biasanya segera setelah itu sebuah exec(3) dilakukan. Jadi, untuk efisiensi yang lebih besar, BSD memperkenalkan vfork() panggilan sistem, yang tidak sepenuhnya menyalin ruang alamat proses induk, tetapi meminjam memori induk dan utas kontrol hingga panggilan ke execve(2) atau keluar terjadi. Proses induk ditangguhkan saat anak menggunakan sumber dayanya. Penggunaan vfork() rumit:misalnya, tidak mengubah data dalam proses induk bergantung pada mengetahui variabel mana yang disimpan dalam register.


Saat Anda memanggil vfork() , proses baru dibuat dan proses baru itu meminjam gambar proses dari proses induk dengan pengecualian tumpukan. Proses anak diberi bintang tumpukan baru sendiri namun tidak memungkinkan untuk return dari fungsi yang memanggil vfork() .

Saat anak berjalan, proses induk diblokir, karena anak meminjam ruang alamat induk.

Terlepas dari apa yang Anda lakukan, semua yang hanya mengakses tumpukan hanya mengubah tumpukan pribadi anak. Namun, jika Anda mengubah data global, ini mengubah data umum dan dengan demikian juga memengaruhi induknya.

Hal-hal yang mengubah data global misalnya:

  • memanggil malloc() atau free()

  • menggunakan stdio

  • mengubah pengaturan sinyal

  • memodifikasi variabel yang bukan lokal ke fungsi yang disebut vfork() .

  • ...

Setelah Anda memanggil _exit() (penting, jangan pernah memanggil exit() ), anak dihentikan dan kontrol diberikan kembali kepada induk.

Jika Anda memanggil fungsi apa pun dari exec*() keluarga, ruang alamat baru dibuat dengan kode program baru, data baru, dan bagian tumpukan dari induk (lihat di bawah). Setelah siap, anak tidak lagi meminjam ruang alamat dari anak, tetapi menggunakan ruang alamat sendiri.

Kontrol diberikan kembali ke induk, karena ruang alamatnya tidak lagi digunakan oleh proses lain.

Penting:Di Linux, tidak ada vfork() yang sebenarnya penerapan. Linux lebih suka mengimplementasikan vfork() berdasarkan Copy on Write fork() konsep yang diperkenalkan oleh SunOS-4.0 pada tahun 1988. Untuk membuat pengguna percaya bahwa mereka menggunakan vfork() , Linux hanya menyiapkan data bersama dan menangguhkan induk sementara anak tidak memanggil _exit() atau salah satu dari exec*() fungsi.

Oleh karena itu, Linux tidak mendapat manfaat dari fakta bahwa vfork() nyata tidak perlu mengatur deskripsi ruang alamat untuk anak di kernel. Ini menghasilkan vfork() yang tidak lebih cepat dari fork() . Pada sistem yang mengimplementasikan vfork() nyata , biasanya 3x lebih cepat dari fork() dan memengaruhi kinerja shell yang menggunakan vfork() - ksh93 , Bourne Shell terbaru dan csh .

Alasan mengapa Anda tidak boleh memanggil exit() dari vfork() ed anak adalah exit() itu membilas stdio jika ada data yang dihapus dari waktu sebelum memanggil vfork() . Ini dapat menyebabkan hasil yang aneh.

BTW:posix_spawn() diimplementasikan di atas vfork() , jadi vfork() tidak akan dihapus dari OS. Telah disebutkan bahwa Linux tidak menggunakan vfork() untuk posix_spawn() .

Untuk tumpukan, hanya ada sedikit dokumentasi, berikut adalah halaman manual Solaris:

 The vfork() and vforkx() functions can normally be used  the
 same  way  as  fork() and forkx(), respectively. The calling
 procedure, however, should not return while running  in  the
 child's  context,  since the eventual return from vfork() or
 vforkx() in the parent would be to a  stack  frame  that  no
 longer  exists. 

Jadi implementasinya dapat melakukan apapun yang disukainya. Implementasi Solaris menggunakan memori bersama untuk kerangka stack dari pemanggilan fungsi vfork() . Tidak ada implementasi yang memberikan akses ke bagian tumpukan yang lebih lama dari induknya.


Linux
  1. Proses Induk Baru Ketika Proses Induk Meninggal?

  2. Mengapa Sigint Tidak Dipropagasi ke Proses Anak Saat Dikirim ke Proses Induknya?

  3. Bagaimana cara membuat proses anak mati setelah orang tua keluar?

  1. Perbedaan antara fork(), vfork(), exec() dan clone()

  2. Mengapa proses anak masih hidup setelah proses induk dimatikan di Linux?

  3. Mengapa pipa shell ini keluar?

  1. Kode Keluar Default Saat Proses Dihentikan?

  2. Bagaimana cara membunuh proses anak python yang dibuat dengan subprocess.check_output() saat induknya meninggal?

  3. Bagaimana saya bisa menghapus pengguna di linux ketika sistem mengatakan sedang digunakan dalam suatu proses