Fork vs Clone pada 2.6 Kernel Linux

37

Saya memiliki beberapa kebingungan mengenai garpu dan klon. Saya telah melihat itu:

  • fork adalah untuk proses dan klon untuk utas

  • garpu hanya memanggil klon, klon digunakan untuk semua proses dan utas

Apakah salah satu dari ini akurat? Apa perbedaan antara 2 syscalls ini dengan kernel Linux 2.6?

Gregg Leventhal
sumber

Jawaban:

52

fork()adalah panggilan sistem UNIX yang asli. Itu hanya dapat digunakan untuk membuat proses baru, bukan utas. Juga, ini portabel.

Di Linux, clone()adalah panggilan sistem baru dan serbaguna yang dapat digunakan untuk membuat utas eksekusi baru. Bergantung pada opsi yang dilewati, utas eksekusi baru dapat mematuhi semantik proses UNIX, utas POSIX, sesuatu di antaranya, atau sesuatu yang sama sekali berbeda (seperti wadah yang berbeda). Anda dapat menentukan segala macam opsi yang menentukan apakah memori, deskriptor file, berbagai ruang nama, penangan sinyal, dan sebagainya untuk dibagikan atau disalin.

Karena clone()ini adalah panggilan sistem superset, implementasi fork()pembungkus panggilan sistem di glibc sebenarnya memanggil clone(), tetapi ini adalah detail implementasi yang tidak perlu diketahui oleh programmer. fork()Panggilan sistem sebenarnya sebenarnya masih ada di kernel Linux untuk alasan kompatibilitas mundur meskipun telah menjadi berlebihan, karena program yang menggunakan versi libc yang sangat lama, atau libc lain selain glibc, mungkin menggunakannya.

clone()juga digunakan untuk mengimplementasikan pthread_create()fungsi POSIX untuk membuat utas.

Program portabel harus memanggil fork()dan pthread_create(), tidak clone().

Celada
sumber
2
posix_spawn adalah fungsi lain yang relevan - keduanya lebih dan lebih portabel daripada garpu dalam beberapa hal.
Random832
10

Tampaknya ada dua clone()hal yang beredar di Linux 2.6

Ada panggilan sistem:

int clone(int (*fn)(void *), void *child_stack,
          int flags, void *arg, ...
          /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );

Ini adalah "clone ()" yang dijelaskan dengan melakukan man 2 clone.

Jika Anda membaca halaman manual itu cukup dekat, Anda akan melihat ini:

It is actually a library function layered on top of the
underlying clone() system call.

Rupanya, Anda seharusnya menerapkan threading menggunakan "fungsi perpustakaan" berlapis pada panggilan sistem yang identik identik.

Saya menulis sebuah program pendek:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int
main(int ac, char **av)
{
    pid_t cpid;
    switch (cpid = fork()) {
    case 0:   // Child process
        break;
    case -1:  // Error
        break;
    default:  // parent process
        break;
    }
    return 0;
}

Kompilasi dengan:, c99 -Wall -Wextradan jalankan di bawah strace -funtuk melihat apa yang sebenarnya dilakukan forking panggilan sistem. Saya mendapatkan ini dari stracepada mesin Linux 2.6.18 (x86_64 CPU):

20097 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2b4ee9213770) = 20098
20097 exit_group(0)                     = ?
20098 exit_group(0)

Tidak ada panggilan "garpu" yang muncul di straceoutput. The clone()panggilan itu menunjukkan sampai di stracekeluaran memiliki argumen yang sangat berbeda dari orang-page-clone. child_stack=0karena argumen pertama berbeda dari int (*fn)(void *).

Tampaknya fork(2)panggilan sistem diimplementasikan dalam hal yang nyata clone() , sama seperti "fungsi perpustakaan" clone()diimplementasikan. The nyata clone() memiliki seperangkat berbeda dari argumen dari orang-page-clone.

Secara sederhana, kedua pernyataan Anda yang tampaknya saling bertentangan fork()dan clone()benar. "Klon" yang terlibat berbeda.

Bruce Ediger
sumber
9
"Ini sebenarnya adalah fungsi pustaka yang berlapis di atas panggilan sistem clone () yang mendasarinya." - secara umum, ini berlaku untuk setiap panggilan sistem. Pemrogram sebenarnya hampir selalu memanggil fungsi dalam libc yang diberi nama setelah panggilan sistem. Ini karena membuat panggilan sistem nyata yang sebenarnya langsung dari C memerlukan sihir khusus platform (biasanya dengan memaksa semacam perangkap CPU, tergantung pada arsitektur ABI) dan kode mesin sebaiknya didelegasikan ke libc.
Celada
1
@Celada - ya, setuju. Hanya saja man 2 cloneungkapan itu persis seperti itu, yang saya pikir membingungkan masalah ini, dan mencegah penanya untuk mendapatkan jawaban yang baik.
Bruce Ediger
2
Saya percaya cara manualnya untuk menunjukkan bahwa daftar argumen dari cloneberbeda fungsi perpustakaan secara substansial dari daftar argumen diterima oleh panggilan sistem yang mendasarinya. Secara khusus, panggilan sistem selalu kembali dua kali pada tumpukan yang sama, seperti cara tradisional fork; semua argumen yang terkait dengan tumpukan anak ditangani secara ketat di ruang pengguna. Lihat misalnya sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/…
zwol
1
Saya ingin memberikan jawaban Anda jawaban terbaik karena itu mengguncang, tetapi saya diombang-ambingkan oleh kawanan dan pergi dengan jawaban pertama. Dia mendapatkan poin untuk waktu respon. Terima kasih atas penjelasan anda
Gregg Leventhal
6

fork()hanyalah serangkaian bendera tertentu untuk panggilan sistem clone(). clone()cukup umum untuk membuat "proses" atau "utas" atau bahkan hal-hal aneh yang berada di suatu tempat antara proses dan utas (misalnya, "proses" yang berbeda yang berbagi tabel deskriptor file yang sama).

Intinya, untuk setiap "jenis" informasi yang terkait dengan konteks eksekusi di kernel, clone()memberi Anda pilihan untuk mengasingkan informasi itu atau menyalinnya. Utas sesuai dengan alias, proses sesuai dengan penyalinan. Dengan menentukan kombinasi tanda tengah untuk clone(), Anda dapat membuat hal-hal aneh yang bukan utas atau proses. Anda biasanya tidak boleh melakukan ini, dan saya membayangkan ada beberapa perdebatan selama pengembangan kernel Linux tentang apakah harus memungkinkan mekanisme umum seperti itu clone().

Atsby
sumber