====== Fork ======
* fork() slouží ke spuštění další instance procesu vytvořením kopie včetně aktuálního kontextu
* oba procesy pokračují v kódu od místa zavolání funkce fork
* proces pozná, zda je potomek nebo rodič, podle návratové hodnoty fork
pid_t pid = fork();
if (pid<0) {
// failed
}
if (pid == 0) {
// child
} else {
// parent
}
* pokud je ukončen rodičovský proces, z potomka se stane sirotek (orphan)
* pokud je ukončen potomek před rodičem, stává se nemrtvým (zombie)
===== likvidace zombie procesů =====
* zombie je proces, který skončil provádění kódu, ale zůstal zapsán v tabulce procesů, aby si rodičovský proces mohl přečíst jeho návratovou hodnotu.
* zombie zůstává v "Terminated state", dokud s tím rodič něco neudělá.
* blokující wait()
* funkce wait čeká na ukončení potomka.
* zavoláme v kódu po vytvoření potomka. Čekání blokuje proces
* neblokující wait()
* zaregistrujeme handler, který při příjmu signálu SIGCHLD zavolá wait()
* zrušení potřeby wait()
* zaregistrujeme handler SIG_IGN a nastavíme flag SA_NOCLDWAIT
* systém pak ukončené potomky rovnou zapracovává
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT;
sigaction(SIGCHLD, &sa, NULL);
* double fork
* vytvoříme potomka a v něm dalšího.
* prvního potomka zabijeme, čímž uděláme z potomka dalšího sirotka
* tohle řešení se prý používá nejčastěji, protože přináší další výhody jako odpojení stdin/out/err od mateřského procesu atd.
pid_t pid1, pid2;
pid1 = fork();
if (pid1 == -1) {
// fork failed
exit(1);
}
if (pid1 == 0) {
// child
pid2 = fork(); //second fork
if (pid2 == -1) {
// fork failed
exit(1);
}
if (pid2 == 0) {
// child
ret = system(cmd);
exit(ret);
}
// parent
exit(0);
}
//parent
waitpid(pid1, &ret, 0);