@Justin, karena kita ingin SO untuk menjadi yang tempat untuk pergi untuk pemrograman pertanyaan.
paxdiablo
4
@ Polaris878: oh, ya sekarang! : D
Janusz Lenar
jadi forkpada dasarnya kloning: O
Sebastian Hojas
Jawaban:
364
Penggunaan forkdan execcontoh semangat UNIX dalam hal ini memberikan cara yang sangat sederhana untuk memulai proses baru.
The forkpanggilan pada dasarnya membuat duplikat dari proses saat ini, identik dalam hampir segala hal. Tidak semuanya disalin (misalnya, batasan sumber daya dalam beberapa implementasi) tetapi idenya adalah untuk membuat salinan sedekat mungkin.
Proses baru (anak) mendapatkan ID proses (PID) yang berbeda dan memiliki PID dari proses lama (induk) sebagai PID induknya (PPID). Karena kedua proses sekarang menjalankan kode yang persis sama, mereka dapat mengetahui yang mana dengan kode pengembalian fork- anak mendapat 0, orang tua mendapat PID anak. Ini semua, tentu saja, dengan asumsi forkpanggilan berfungsi - jika tidak, tidak ada anak yang dibuat dan orang tua mendapat kode kesalahan.
The execpanggilan adalah cara untuk dasarnya menggantikan proses saat ini seluruh dengan program baru. Itu memuat program ke dalam ruang proses saat ini dan menjalankannya dari titik masuk.
Jadi, forkdan execsering digunakan secara berurutan untuk menjalankan program baru sebagai anak dari proses saat ini. Kerang biasanya melakukan ini setiap kali Anda mencoba menjalankan program seperti find- garpu garpu, kemudian anak memuat findprogram ke dalam memori, mengatur semua argumen baris perintah, I / O standar dan sebagainya.
Tapi mereka tidak diharuskan untuk digunakan bersama. Sangat dapat diterima untuk suatu program untuk forkdirinya sendiri tanpa exec, jika, misalnya, program tersebut berisi kode induk dan anak (Anda harus berhati-hati dengan apa yang Anda lakukan, setiap implementasi mungkin memiliki batasan). Ini digunakan cukup banyak (dan masih) untuk daemon yang hanya mendengarkan pada port TCP dan forksalinannya sendiri untuk memproses permintaan tertentu sementara orangtua kembali mendengarkan.
Demikian pula, program yang tahu mereka sudah selesai dan hanya ingin menjalankan program lain tidak perlu fork, execdan kemudian waituntuk anak. Mereka hanya dapat memuat anak langsung ke ruang proses mereka.
Beberapa implementasi UNIX telah dioptimalkan forkyang menggunakan apa yang mereka sebut copy-on-write. Ini adalah trik untuk menunda penyalinan ruang proses forkhingga program mencoba mengubah sesuatu di ruang itu. Ini berguna untuk program-program yang hanya menggunakan forkdan tidak execkarena mereka tidak perlu menyalin seluruh ruang proses.
Jika execini disebut berikut fork(dan ini adalah apa yang terjadi kebanyakan), yang menyebabkan tulis ke ruang proses dan kemudian disalin untuk proses anak.
Perhatikan bahwa ada seluruh keluarga execpanggilan ( execl, execle, execvedan sebagainya), tetapi execdalam konteks di sini berarti salah satu dari mereka.
Diagram berikut menggambarkan fork/execoperasi khas di mana bashshell digunakan untuk mendaftar direktori dengan lsperintah:
+--------+| pid=7|| ppid=4|| bash |+--------+|| calls fork
V
+--------++--------+| pid=7| forks | pid=22|| ppid=4|---------->| ppid=7|| bash || bash |+--------++--------+||| waits for pid 22| calls exec to run ls
| V
|+--------+|| pid=22||| ppid=7||| ls |
V +--------++--------+|| pid=7|| exits
| ppid=4|<---------------+| bash |+--------+|| continues
V
fork()membagi proses saat ini menjadi dua proses. Atau dengan kata lain, program linier Anda yang mudah dipikirkan tiba-tiba menjadi dua program terpisah yang menjalankan satu kode:
int pid = fork();if(pid ==0){
printf("I'm the child");}else{
printf("I'm the parent, my child is %i", pid);// here we can kill the child, but that's not very parently of us}
Ini bisa meledakkan pikiran Anda. Sekarang Anda memiliki satu kode dengan kondisi identik yang dijalankan oleh dua proses. Proses anak mewarisi semua kode dan memori dari proses yang baru saja dibuat itu, termasuk mulai dari mana fork()panggilan baru saja tinggalkan. Satu-satunya perbedaan adalah fork()kode pengembalian untuk memberi tahu Anda jika Anda adalah orang tua atau anak. Jika Anda adalah orang tua, nilai kembali adalah id anak.
execsedikit lebih mudah untuk dipahami, Anda hanya mengatakan execuntuk mengeksekusi proses menggunakan target yang dapat dieksekusi dan Anda tidak memiliki dua proses menjalankan kode yang sama atau mewarisi keadaan yang sama. Seperti kata @Steve Hawkins, execdapat digunakan setelah Anda forkmengeksekusi dalam proses saat ini target yang dapat dieksekusi.
ada juga kondisi ketika pid < 0dan fork()panggilan gagal
Jonathan Fingland
3
Itu sama sekali tidak mengejutkan saya :-) Sepotong kode yang dieksekusi oleh dua proses terjadi setiap kali shared library atau DLL digunakan.
paxdiablo
31
Saya pikir beberapa konsep dari "Advanced Unix Programming" oleh Marc Rochkind sangat membantu dalam memahami peran yang berbeda dari fork()/ exec(), terutama untuk seseorang yang terbiasa dengan CreateProcess()model Windows :
Sebuah Program adalah kumpulan instruksi dan data yang disimpan dalam file biasa pada disk. (dari 1.1.2 Program, Proses, dan Utas)
.
Untuk menjalankan program, kernel pertama kali diminta untuk membuat proses baru , yang merupakan lingkungan di mana suatu program dijalankan. (juga dari 1.1.2 Program, Proses, dan Utas)
.
Tidak mungkin untuk memahami panggilan sistem eksekutif atau garpu tanpa sepenuhnya memahami perbedaan antara suatu proses dan program. Jika ketentuan ini baru bagi Anda, Anda mungkin ingin kembali dan meninjau Bagian 1.1.2. Jika Anda siap untuk melanjutkan sekarang, kami akan meringkas perbedaan dalam satu kalimat: Proses adalah lingkungan eksekusi yang terdiri dari segmen instruksi, data pengguna, dan data sistem, serta banyak sumber daya lain yang diperoleh saat runtime , sedangkan program adalah file yang berisi instruksi dan data yang digunakan untuk menginisialisasi instruksi dan segmen data pengguna dari suatu proses. (dari 5.3 execPanggilan Sistem)
Setelah Anda memahami perbedaan antara program dan proses, perilaku fork()dan exec()fungsi dapat diringkas sebagai:
fork() membuat duplikat dari proses saat ini
exec() mengganti program dalam proses saat ini dengan program lain
Fork membuat salinan proses panggilan. umumnya mengikuti struktur
int cpid = fork();if(cpid ==0){//child code
exit(0);}//parent code
wait(cpid);// end
(untuk teks proses anak (kode), data, tumpukan sama dengan proses panggilan) proses anak mengeksekusi kode dalam blok if.
EXEC menggantikan proses saat ini dengan kode, data, tumpukan proses baru. umumnya mengikuti struktur
int cpid = fork();if(cpid ==0){//child code
exec(foo);
exit(0);}//parent code
wait(cpid);// end
(setelah exec panggil unix kernel menghapus teks proses anak, data, tumpukan dan isi dengan teks / data terkait proses foo) sehingga proses anak adalah dengan kode yang berbeda (kode foo {tidak sama dengan induk})
Ini agak tidak berhubungan dengan pertanyaan tetapi bukankah kode ini di atas menyebabkan kondisi lomba jika proses anak kebetulan menyelesaikan kode itu terlebih dahulu? Dalam hal ini, proses orangtua akan berkeliaran selamanya menunggu anak untuk mengakhiri sendiri, kan?
stdout
7
Mereka digunakan bersama untuk membuat proses anak baru. Pertama, panggilan forkmenciptakan salinan dari proses saat ini (proses anak). Kemudian, execdipanggil dari dalam proses anak untuk "mengganti" salinan proses induk dengan proses baru.
Prosesnya kira-kira seperti ini:
child = fork();//Fork returns a PID for the parent process, or 0 for the child, or -1 for Failif(child <0){
std::cout <<"Failed to fork GUI process...Exiting"<< std::endl;
exit (-1);}elseif(child ==0){// This is the Child Process// Call one of the "exec" functions to create the child process
execvp (argv[0],const_cast<char**>(argv));}else{// This is the Parent Process//Continue executing parent process}
Pada baris ke-7 disebutkan bahwa fungsi exec () menciptakan proses anak .. Apakah benar demikian karena fork () telah membuat proses anak dan exec () memanggil hanya menggantikan program dari proses baru yang baru saja dibuat
cbinder
4
fork () membuat salinan dari proses saat ini, dengan eksekusi pada anak baru dimulai dari setelah panggilan fork (). Setelah fork (), mereka identik, kecuali untuk nilai balik dari fungsi fork (). (RTFM untuk lebih jelasnya.) Kedua proses kemudian dapat menyimpang lebih jauh, dengan satu tidak dapat mengganggu yang lain, kecuali mungkin melalui semua file menangani.
exec () menggantikan proses saat ini dengan yang baru. Ini tidak ada hubungannya dengan fork (), kecuali bahwa exec () sering mengikuti fork () ketika yang diinginkan adalah meluncurkan proses anak yang berbeda, daripada menggantikan yang sekarang.
The fork()system call menciptakan klon dari program yang sedang berjalan. Program asli melanjutkan eksekusi dengan baris kode berikutnya setelah panggilan fungsi fork (). Klon juga memulai eksekusi pada baris kode berikutnya. Lihatlah kode berikut yang saya dapatkan dari http://timmurphy.org/2014/04/26/using-fork-in-cc-a-minimum-working-example/
#include<stdio.h>#include<unistd.h>int main(int argc,char**argv){
printf("--beginning of program\n");int counter =0;pid_t pid = fork();if(pid ==0){// child processint i =0;for(; i <5;++i){
printf("child process: counter=%d\n",++counter);}}elseif(pid >0){// parent processint j =0;for(; j <5;++j){
printf("parent process: counter=%d\n",++counter);}}else{// fork failed
printf("fork() failed!\n");return1;}
printf("--end of program--\n");return0;}
Program ini mendeklarasikan variabel penghitung, atur ke nol, sebelum fork()ing. Setelah panggilan fork, kami memiliki dua proses yang berjalan secara paralel, keduanya menambah versi counter mereka sendiri. Setiap proses akan berjalan sampai selesai dan keluar. Karena proses berjalan secara paralel, kami tidak memiliki cara untuk mengetahui mana yang akan selesai terlebih dahulu. Menjalankan program ini akan mencetak sesuatu yang mirip dengan yang ditunjukkan di bawah ini, meskipun hasilnya dapat bervariasi dari satu lari ke yang berikutnya.
--beginning of program
parent process: counter=1
parent process: counter=2
parent process: counter=3
child process: counter=1
parent process: counter=4
child process: counter=2
parent process: counter=5
child process: counter=3--end of program--
child process: counter=4
child process: counter=5--end of program--
The exec()keluarga panggilan sistem menggantikan kode saat ini melaksanakan proses dengan sepotong kode. Proses mempertahankan PID-nya tetapi menjadi program baru. Misalnya, pertimbangkan kode berikut:
#include<stdio.h>#include<unistd.h>
main(){char program[80],*args[3];int i;
printf("Ready to exec()...\n");
strcpy(program,"date");
args[0]="date";
args[1]="-u";
args[2]=NULL;
i=execvp(program,args);
printf("i=%d ... did it work?\n",i);}
Program ini memanggil execvp()fungsi untuk mengganti kodenya dengan program tanggal. Jika kode disimpan dalam file bernama exec1.c, maka mengeksekusinya menghasilkan output berikut:
Ready to exec()...TueJul1520:17:53 UTC 2008
Program mengeluarkan baris ―Ready to exec (). . . ‖ Dan setelah memanggil fungsi execvp (), ganti kodenya dengan program tanggal. Perhatikan bahwa garis -. . . tidak berfungsi‖ tidak ditampilkan, karena pada saat itu kode telah diganti. Sebagai gantinya, kami melihat output dari mengeksekusi ―date -u.‖
Ini menciptakan salinan proses yang sedang berjalan. Proses yang berjalan disebut proses induk & proses yang baru dibuat disebut proses anak . Cara untuk membedakan keduanya adalah dengan melihat nilai yang dikembalikan:
fork() mengembalikan pengidentifikasi proses (pid) dari proses anak di orang tua
fork() mengembalikan 0 pada anak.
exec():
Ini memulai proses baru dalam suatu proses. Itu memuat program baru ke dalam proses saat ini, menggantikan yang sudah ada.
fork()+ exec():
Ketika meluncurkan program baru adalah pertama fork(), menciptakan proses baru, dan kemudian exec()(yaitu memuat ke dalam memori dan mengeksekusi) program biner yang seharusnya dijalankan.
int main(void){int pid = fork();if( pid ==0){
execvp("find", argv );}//Put the parent to sleep for 2 sec,let the child finished executing
wait(2);return0;}
Contoh utama untuk memahami fork()dan exec()konsep adalah shell , program interpreter perintah yang biasanya dijalankan pengguna setelah masuk ke sistem. Shell mengartikan kata pertama dari baris perintah sebagai nama perintah
Untuk banyak perintah, shell garpu dan proses anak eksekutif perintah terkait dengan nama mengobati kata-kata yang tersisa pada baris perintah sebagai parameter untuk perintah.
The shell memungkinkan tiga jenis perintah. Pertama, perintah dapat berupa file yang dapat
dieksekusi yang berisi kode objek yang dihasilkan oleh kompilasi kode sumber (misalnya program C). Kedua, perintah bisa berupa file yang dapat dieksekusi yang berisi urutan baris perintah shell. Akhirnya, sebuah perintah dapat berupa perintah shell internal (bukan file yang dapat dieksekusi ex-> cd , ls dll.)
fork
pada dasarnya kloning: OJawaban:
Penggunaan
fork
danexec
contoh semangat UNIX dalam hal ini memberikan cara yang sangat sederhana untuk memulai proses baru.The
fork
panggilan pada dasarnya membuat duplikat dari proses saat ini, identik dalam hampir segala hal. Tidak semuanya disalin (misalnya, batasan sumber daya dalam beberapa implementasi) tetapi idenya adalah untuk membuat salinan sedekat mungkin.Proses baru (anak) mendapatkan ID proses (PID) yang berbeda dan memiliki PID dari proses lama (induk) sebagai PID induknya (PPID). Karena kedua proses sekarang menjalankan kode yang persis sama, mereka dapat mengetahui yang mana dengan kode pengembalian
fork
- anak mendapat 0, orang tua mendapat PID anak. Ini semua, tentu saja, dengan asumsifork
panggilan berfungsi - jika tidak, tidak ada anak yang dibuat dan orang tua mendapat kode kesalahan.The
exec
panggilan adalah cara untuk dasarnya menggantikan proses saat ini seluruh dengan program baru. Itu memuat program ke dalam ruang proses saat ini dan menjalankannya dari titik masuk.Jadi,
fork
danexec
sering digunakan secara berurutan untuk menjalankan program baru sebagai anak dari proses saat ini. Kerang biasanya melakukan ini setiap kali Anda mencoba menjalankan program sepertifind
- garpu garpu, kemudian anak memuatfind
program ke dalam memori, mengatur semua argumen baris perintah, I / O standar dan sebagainya.Tapi mereka tidak diharuskan untuk digunakan bersama. Sangat dapat diterima untuk suatu program untuk
fork
dirinya sendiri tanpaexec
, jika, misalnya, program tersebut berisi kode induk dan anak (Anda harus berhati-hati dengan apa yang Anda lakukan, setiap implementasi mungkin memiliki batasan). Ini digunakan cukup banyak (dan masih) untuk daemon yang hanya mendengarkan pada port TCP danfork
salinannya sendiri untuk memproses permintaan tertentu sementara orangtua kembali mendengarkan.Demikian pula, program yang tahu mereka sudah selesai dan hanya ingin menjalankan program lain tidak perlu
fork
,exec
dan kemudianwait
untuk anak. Mereka hanya dapat memuat anak langsung ke ruang proses mereka.Beberapa implementasi UNIX telah dioptimalkan
fork
yang menggunakan apa yang mereka sebut copy-on-write. Ini adalah trik untuk menunda penyalinan ruang prosesfork
hingga program mencoba mengubah sesuatu di ruang itu. Ini berguna untuk program-program yang hanya menggunakanfork
dan tidakexec
karena mereka tidak perlu menyalin seluruh ruang proses.Jika
exec
ini disebut berikutfork
(dan ini adalah apa yang terjadi kebanyakan), yang menyebabkan tulis ke ruang proses dan kemudian disalin untuk proses anak.Perhatikan bahwa ada seluruh keluarga
exec
panggilan (execl
,execle
,execve
dan sebagainya), tetapiexec
dalam konteks di sini berarti salah satu dari mereka.Diagram berikut menggambarkan
fork/exec
operasi khas di manabash
shell digunakan untuk mendaftar direktori denganls
perintah:sumber
fork()
membagi proses saat ini menjadi dua proses. Atau dengan kata lain, program linier Anda yang mudah dipikirkan tiba-tiba menjadi dua program terpisah yang menjalankan satu kode:Ini bisa meledakkan pikiran Anda. Sekarang Anda memiliki satu kode dengan kondisi identik yang dijalankan oleh dua proses. Proses anak mewarisi semua kode dan memori dari proses yang baru saja dibuat itu, termasuk mulai dari mana
fork()
panggilan baru saja tinggalkan. Satu-satunya perbedaan adalahfork()
kode pengembalian untuk memberi tahu Anda jika Anda adalah orang tua atau anak. Jika Anda adalah orang tua, nilai kembali adalah id anak.exec
sedikit lebih mudah untuk dipahami, Anda hanya mengatakanexec
untuk mengeksekusi proses menggunakan target yang dapat dieksekusi dan Anda tidak memiliki dua proses menjalankan kode yang sama atau mewarisi keadaan yang sama. Seperti kata @Steve Hawkins,exec
dapat digunakan setelah Andafork
mengeksekusi dalam proses saat ini target yang dapat dieksekusi.sumber
pid < 0
danfork()
panggilan gagalSaya pikir beberapa konsep dari "Advanced Unix Programming" oleh Marc Rochkind sangat membantu dalam memahami peran yang berbeda dari
fork()
/exec()
, terutama untuk seseorang yang terbiasa denganCreateProcess()
model Windows :.
.
Setelah Anda memahami perbedaan antara program dan proses, perilaku
fork()
danexec()
fungsi dapat diringkas sebagai:fork()
membuat duplikat dari proses saat iniexec()
mengganti program dalam proses saat ini dengan program lain(pada dasarnya ini adalah versi 'for dummies' yang disederhanakan dari jawaban paxdiablo yang jauh lebih terperinci )
sumber
Fork membuat salinan proses panggilan. umumnya mengikuti struktur
(untuk teks proses anak (kode), data, tumpukan sama dengan proses panggilan) proses anak mengeksekusi kode dalam blok if.
EXEC menggantikan proses saat ini dengan kode, data, tumpukan proses baru. umumnya mengikuti struktur
(setelah exec panggil unix kernel menghapus teks proses anak, data, tumpukan dan isi dengan teks / data terkait proses foo) sehingga proses anak adalah dengan kode yang berbeda (kode foo {tidak sama dengan induk})
sumber
Mereka digunakan bersama untuk membuat proses anak baru. Pertama, panggilan
fork
menciptakan salinan dari proses saat ini (proses anak). Kemudian,exec
dipanggil dari dalam proses anak untuk "mengganti" salinan proses induk dengan proses baru.Prosesnya kira-kira seperti ini:
sumber
fork () membuat salinan dari proses saat ini, dengan eksekusi pada anak baru dimulai dari setelah panggilan fork (). Setelah fork (), mereka identik, kecuali untuk nilai balik dari fungsi fork (). (RTFM untuk lebih jelasnya.) Kedua proses kemudian dapat menyimpang lebih jauh, dengan satu tidak dapat mengganggu yang lain, kecuali mungkin melalui semua file menangani.
exec () menggantikan proses saat ini dengan yang baru. Ini tidak ada hubungannya dengan fork (), kecuali bahwa exec () sering mengikuti fork () ketika yang diinginkan adalah meluncurkan proses anak yang berbeda, daripada menggantikan yang sekarang.
sumber
Perbedaan utama antara
fork()
danexec()
adalah,The
fork()
system call menciptakan klon dari program yang sedang berjalan. Program asli melanjutkan eksekusi dengan baris kode berikutnya setelah panggilan fungsi fork (). Klon juga memulai eksekusi pada baris kode berikutnya. Lihatlah kode berikut yang saya dapatkan dari http://timmurphy.org/2014/04/26/using-fork-in-cc-a-minimum-working-example/Program ini mendeklarasikan variabel penghitung, atur ke nol, sebelum
fork()
ing. Setelah panggilan fork, kami memiliki dua proses yang berjalan secara paralel, keduanya menambah versi counter mereka sendiri. Setiap proses akan berjalan sampai selesai dan keluar. Karena proses berjalan secara paralel, kami tidak memiliki cara untuk mengetahui mana yang akan selesai terlebih dahulu. Menjalankan program ini akan mencetak sesuatu yang mirip dengan yang ditunjukkan di bawah ini, meskipun hasilnya dapat bervariasi dari satu lari ke yang berikutnya.The
exec()
keluarga panggilan sistem menggantikan kode saat ini melaksanakan proses dengan sepotong kode. Proses mempertahankan PID-nya tetapi menjadi program baru. Misalnya, pertimbangkan kode berikut:Program ini memanggil
execvp()
fungsi untuk mengganti kodenya dengan program tanggal. Jika kode disimpan dalam file bernama exec1.c, maka mengeksekusinya menghasilkan output berikut:Program mengeluarkan baris ―Ready to exec (). . . ‖ Dan setelah memanggil fungsi execvp (), ganti kodenya dengan program tanggal. Perhatikan bahwa garis -. . . tidak berfungsi‖ tidak ditampilkan, karena pada saat itu kode telah diganti. Sebagai gantinya, kami melihat output dari mengeksekusi ―date -u.‖
sumber
fork()
:Ini menciptakan salinan proses yang sedang berjalan. Proses yang berjalan disebut proses induk & proses yang baru dibuat disebut proses anak . Cara untuk membedakan keduanya adalah dengan melihat nilai yang dikembalikan:
fork()
mengembalikan pengidentifikasi proses (pid) dari proses anak di orang tuafork()
mengembalikan 0 pada anak.exec()
:Ini memulai proses baru dalam suatu proses. Itu memuat program baru ke dalam proses saat ini, menggantikan yang sudah ada.
fork()
+exec()
:Ketika meluncurkan program baru adalah pertama
fork()
, menciptakan proses baru, dan kemudianexec()
(yaitu memuat ke dalam memori dan mengeksekusi) program biner yang seharusnya dijalankan.sumber
Contoh utama untuk memahami
fork()
danexec()
konsep adalah shell , program interpreter perintah yang biasanya dijalankan pengguna setelah masuk ke sistem. Shell mengartikan kata pertama dari baris perintah sebagai nama perintahUntuk banyak perintah, shell garpu dan proses anak eksekutif perintah terkait dengan nama mengobati kata-kata yang tersisa pada baris perintah sebagai parameter untuk perintah.
The shell memungkinkan tiga jenis perintah. Pertama, perintah dapat berupa file yang dapat dieksekusi yang berisi kode objek yang dihasilkan oleh kompilasi kode sumber (misalnya program C). Kedua, perintah bisa berupa file yang dapat dieksekusi yang berisi urutan baris perintah shell. Akhirnya, sebuah perintah dapat berupa perintah shell internal (bukan file yang dapat dieksekusi ex-> cd , ls dll.)
sumber