Arasındaki farklar nelerdir fork
ve exec
?
fork
temelde klonlama: O
Arasındaki farklar nelerdir fork
ve exec
?
fork
temelde klonlama: O
Yanıtlar:
Yeni süreçlere başlamak için çok basit bir yol sağladığı için UNIX ruhunu kullanmak fork
ve exec
örneklendirmek.
fork
Çağrı temelde özdeş, mevcut sürecin yinelenen yapar neredeyse her şekilde. Her şey kopyalanmaz (örneğin, bazı uygulamalarda kaynak sınırları), ancak amaç, olabildiğince yakın bir kopya oluşturmaktır.
Yeni işlem (alt) farklı bir işlem kimliği (PID) alır ve üst PID (PPID) olarak eski işlemin (üst öğe) PID'sine sahiptir. İki işlem artık tam olarak aynı kodu çalıştırdığından, hangisinin dönüş koduyla hangisinin fork
0 olduğunu, ebeveynin çocuğun PID'sini aldığını söyleyebilirler . Tabii ki, bu, fork
çağrının işe yaradığı varsayılarak varsayılır - eğer değilse, hiçbir çocuk oluşturulmaz ve ebeveyn bir hata kodu alır.
exec
Çağrı temelde yeni bir program ile tüm geçerli süreci değiştirmek için bir yoldur. Programı geçerli işlem alanına yükler ve giriş noktasından çalıştırır.
Yani, fork
ve exec
genellikle mevcut sürecin bir çocuk olarak çalışan yeni bir program almak için sırayla kullanılmaktadır. Kabuklar genellikle find
kabuk çatalları gibi bir programı çalıştırmaya çalıştığınızda bunu yapar , daha sonra çocuk find
programı belleğe yükler, tüm komut satırı argümanlarını, standart G / Ç vb.
Ancak birlikte kullanılmaları gerekmez. Örneğin, programın hem ebeveyn hem de alt kod içerip içermediğini fork
bilmeden bir programın kendisi için mükemmel kabul edilebilir exec
(ne yaptığınıza dikkat etmeniz gerekir, her uygulamanın kısıtlamaları olabilir). Bu, fork
ebeveyn dinlemeye geri dönerken belirli bir isteği işlemek için bir TCP bağlantı noktasını ve kendilerinin bir kopyasını dinleyen daemonlar için oldukça fazla (ve hala) kullanıldı .
Benzer şekilde, bitmiş olduğunu biliyorum ve programlar sadece gerekmez başka bir programı çalıştırmak istiyorum fork
, exec
ve sonra wait
çocuk için. Çocuğu doğrudan işlem alanlarına yükleyebilirler.
Bazı UNIX uygulamalarında, fork
üzerine yazma kopyası adını verdikleri optimize edilmiş bir uygulama vardır . Bu, fork
program o alandaki bir şeyi değiştirmeye çalışana kadar işlem alanının kopyalanmasını geciktiren bir hiledir . Bu, yalnızca kullanarak bu programlar için yararlıdır fork
ve exec
bunlar bütün bir süreç alanını kopyalamak gerekmez ki.
Eğer exec
edilir Aşağıdaki denilen fork
(ve bu çoğunlukla böyle olur), bu süreç uzaya bir yazma neden olur ve daha sonra alt sürecin kopyalanır.
Bütün bir aile olduğunu Not exec
aramaları ( execl
, execle
, execve
vb) ama exec
bağlamda burada bunlardan herhangi biri anlamına gelir.
Aşağıdaki diyagram fork/exec
, bash
kabuğun ls
komutla bir dizini listelemek için kullanıldığı tipik işlemi göstermektedir :
+--------+
| 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()
mevcut işlemi iki işleme böler. Ya da başka bir deyişle, güzel doğrusal düşünmek kolay program aniden bir kod parçası çalışan iki ayrı program olur:
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
}
Bu biraz aklınızı başınızdan alabilir. Şimdi, iki işlem tarafından yürütülen özdeş durumun aynısı olan bir kod parçanız var. Alt işlem, fork()
çağrının kaldığı yerden başlamak da dahil olmak üzere, onu oluşturan işlemin tüm kodunu ve belleğini devralır . Tek fark, fork()
ebeveyn veya çocuk olup olmadığınızı size bildiren dönüş kodudur. Üst öğe sizseniz, dönüş değeri çocuğun kimliğidir.
exec
kavramak biraz daha kolay, sadece exec
hedef yürütülebilir dosyayı kullanarak bir işlem yürütmenizi söylersiniz ve aynı kodu çalıştıran veya aynı durumu devralan iki işleminiz yoktur. @Steve Hawkins'in dediği gibi, mevcut işlemde hedef yürütülebilir dosyayı yürütmek exec
için kullanılabilir fork
.
pid < 0
ve fork()
arama başarısız olduğunda da durum var
Marc Rochkind'in "Gelişmiş Unix Programlaması" ndan bazı kavramların , fork()
/ exec()
özellikle Windows CreateProcess()
modeline alışkın olan biri için farklı rollerinin anlaşılmasında yardımcı olduğunu düşünüyorum :
Bir program, diskte düzenli dosyada tutulur talimatlar ve verilerin bir topluluğudur. (1.1.2 Programlar, Süreçler ve Konular'dan)
.
Bir programı çalıştırmak için, çekirdekten önce bir programın yürütüldüğü bir ortam olan yeni bir işlem yaratması istenir . (ayrıca 1.1.2 Programlar, İşlemler ve Konular'dan)
.
Bir işlem ve program arasındaki ayrımı tam olarak anlamadan exec veya fork sistem çağrılarını anlamak imkansızdır. Bu şartlar sizin için yeniyse, geri dönüp Bölüm 1.1.2'yi gözden geçirmek isteyebilirsiniz. Şimdi ilerlemeye hazırsanız, tek bir cümledeki farkı özetleyeceğiz: Süreç, talimat, kullanıcı verileri ve sistem veri bölümlerinin yanı sıra çalışma zamanında edinilen diğer birçok kaynaktan oluşan bir yürütme ortamıdır bir program ise, bir sürecin talimat ve kullanıcı-veri segmentlerini başlatmak için kullanılan talimatları ve verileri içeren bir dosyadır. (5.3
exec
Sistem Çağrılarından)
Bir program ile bir süreç arasındaki farkı anladıktan sonra, fork()
ve exec()
fonksiyonunun davranışı şöyle özetlenebilir:
fork()
geçerli işlemin bir kopyasını oluştururexec()
geçerli işlemdeki programı başka bir programla değiştirir(bu aslında paxdiablo'nun çok daha ayrıntılı cevabının basitleştirilmiş bir 'aptallar için' versiyonudur )
Fork, çağrı sürecinin bir kopyasını oluşturur. genellikle yapıyı takip eder
int cpid = fork( );
if (cpid = = 0)
{
//child code
exit(0);
}
//parent code
wait(cpid);
// end
(alt işlem metni (kod), veri, yığın çağırma işlemi ile aynıdır) alt işlem if bloğundaki kodu yürütür.
EXEC, mevcut işlemi yeni işlemin kodu, verileri, yığını ile değiştirir. genellikle yapıyı takip eder
int cpid = fork( );
if (cpid = = 0)
{
//child code
exec(foo);
exit(0);
}
//parent code
wait(cpid);
// end
(exec çağrısından sonra unix çekirdeği alt işlem metnini, verileri, yığını ve foo işlemiyle ilgili metin / verileri doldurur) bu nedenle alt işlem farklı kodlarla (foo'nun kodu {ebeveyn ile aynı değildir})
Birlikte yeni bir alt süreç oluşturmak için kullanılırlar. İlk olarak, çağrı fork
geçerli işlemin (alt işlem) bir kopyasını oluşturur. Ardından, exec
üst işlemin kopyasını yeni işlemle "değiştirmek" için alt işlem içinden çağrılır.
Süreç böyle bir şeye gider:
child = fork(); //Fork returns a PID for the parent process, or 0 for the child, or -1 for Fail
if (child < 0) {
std::cout << "Failed to fork GUI process...Exiting" << std::endl;
exit (-1);
} else if (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
}
fork () geçerli işlemin bir kopyasını oluşturur ve yeni alt öğede yürütme fork () çağrısından hemen sonra başlar. Fork () işlevinden sonra, fork () işlevinin dönüş değeri dışında aynıdır. (Daha fazla ayrıntı için RTFM.) Bu iki işlem daha da farklı olabilir, biri paylaşılan dosya tanıtıcıları dışında biri diğerine müdahale edemez.
exec (), geçerli işlemi yenisiyle değiştirir. Fork () ile bir ilgisi yoktur, ancak bir exec () genellikle geçerli olanı değiştirmek yerine farklı bir alt süreç başlatmak olduğunda fork () 'u takip eder.
Arasındaki temel fark, fork()
ve exec()
, yani
fork()
Sistem çağrısı Çalışmakta programın bir klon yaratır. Orijinal program fork () fonksiyon çağrısından sonraki kod satırıyla çalışmaya devam eder. Klon ayrıca bir sonraki kod satırında yürütülmeye başlar. İ aldığım o aşağıdaki koda bak 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 process
int i = 0;
for (; i < 5; ++i)
{
printf("child process: counter=%d\n", ++counter);
}
}
else if (pid > 0)
{
// parent process
int j = 0;
for (; j < 5; ++j)
{
printf("parent process: counter=%d\n", ++counter);
}
}
else
{
// fork failed
printf("fork() failed!\n");
return 1;
}
printf("--end of program--\n");
return 0;
}
Bu program ing'den önce sıfıra ayarlanmış bir sayaç değişkeni bildirir fork()
. Çatal çağrısından sonra, paralel olarak çalışan iki işlemimiz var, her ikisi de kendi sayaç sürümünü arttırıyor. Her işlem tamamlanıp çıkılacaktır. Süreçler paralel ilerlediğinden, hangisinin önce biteceğini bilmenin hiçbir yolu yoktur. Bu programı çalıştırmak, aşağıda gösterilene benzer bir şey yazdıracak, ancak sonuçlar bir işlemden diğerine değişebilir.
--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--
exec()
Sistem aramaların aile başka bir kod parçası ile bir sürecin şu anda yürütülen kodu yerine geçer. Süreç PID'sini korur, ancak yeni bir program haline gelir. Örneğin, aşağıdaki kodu göz önünde bulundurun:
#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);
}
Bu program execvp()
, kodunu tarih programıyla değiştirmek için işlevi çağırır . Kod exec1.c adlı bir dosyada depolanırsa, yürütülmesi aşağıdaki çıktıyı üretir:
Ready to exec()...
Tue Jul 15 20:17:53 UTC 2008
Program, exec exec () 'ye hazır satırını çıkarır. . . ‖ Ve execvp () işlevini çağırdıktan sonra, kodunu tarih programıyla değiştirir. Unutmayın çizgi -. . . işe yaramadı mı? görüntülenmez, çünkü bu noktada kod değiştirilmiştir. Bunun yerine, ―date -u.‖ yürütme çıktısını görüyoruz.
Çalışan işlemin bir kopyasını oluşturur. Çalışan sürece üst süreç , yeni oluşturulan sürece alt süreç denir . İkisini ayırt etmenin yolu döndürülen değere bakmaktır:
fork()
Üst öğedeki alt işlemin işlem tanımlayıcısını (pid) döndürür
fork()
alt öğede 0 değerini döndürür.
exec()
:
Bir süreç içinde yeni bir süreç başlatır. Mevcut işleme yeni bir program yükler ve mevcut programı değiştirir.
fork()
+ exec()
:
Yeni bir program başlatırken, öncelikle fork()
yeni bir işlem oluşturmak ve daha sonra exec()
çalıştırması gereken program ikili dosyasını (yani belleğe yükleyin ve yürütmek).
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 );
return 0;
}
Başlıca örneği anlamak fork()
ve exec()
kavramdır kabuk , kullanıcılar genellikle sistemle kabuğu içine giriş yaptıktan sonra yürütür o komut yorumlayıcı programı ilk kelimeyi yorumladığı komut satırında bir şekilde komut adı
Birçok komut için, kabuk çatalları ve alt işlem , komut satırında kalan sözcükleri komuta parametre olarak ele alan adla ilişkili komutu yürütür .
Kabuk komutları üç tip sağlar. Birincisi, bir komut, kaynak kodun derlenmesi ile üretilen nesne kodunu (örneğin bir C programı) içeren yürütülebilir bir dosya olabilir . İkinci olarak, bir komut bir dizi kabuk komut satırı içeren yürütülebilir bir dosya olabilir. Son olarak, bir komut dahili bir kabuk komutu olabilir. ( Cd , ls vb. Yürütülebilir bir dosya yerine )