Eh, evo opet ja…
Prije nego pokusam dati odgovor na tvoje pitanje, navodim izlaz koji generise tvoj program na mom racunaru:
[kk]$ ./babysitter
Ja sam roditelj (pid = 942) sa petoro djece:
Proces 1 krenuo
Proces 2 krenuo
Proces 3 krenuo
Proces 5 krenuo
Proces 4 krenuo
pid[0] = 943
pid[1] = 944
pid[2] = 945
pid[3] = 946
pid[4] = 947
[kk]$ Proces 5 zavrsava
Ja sam dijete (pid = 947), a moj roditelj je (pid = 1)
Proces 4 zavrsava
Ja sam dijete (pid = 946), a moj roditelj je (pid = 1)
Proces 3 zavrsava
Ja sam dijete (pid = 945), a moj roditelj je (pid = 1)
Proces 2 zavrsava
Ja sam dijete (pid = 944), a moj roditelj je (pid = 1)
Proces 1 zavrsava
Ja sam dijete (pid = 943), a moj roditelj je (pid = 1)
_
… i ceka. Ako pritisnes ENTER, vrati se u shell. U cemu je fol?
Ako pazljivo pogledas, vidjeces da se nakon ispisa koji generise “babo” pojavio shell prompt. Odgovor na pitanje zasto je to tako lezi u slijedecem odlomku koda:
for (i = 0; i < 5; i++)
printf("pid[%u] = %un", i, pid[i]);
exit(0);
for (i = 0; i < 5; i++)
waitpid(pid[i], NULL, 0);
Dakle, kada babo ispise pid-ove svoje djece, on odmah umre (pozove exit), i ne uspije sacekati da se njegova djeca zavrse. Zato se odmah nakon ispisa pojavljuje shell prompt, dok djeca jos uvijek ferceraju. Prvo dijete koje terminira je 5 (nakon 2 sekunde) i pojavljuje se poruka “Proces 5 zavrsava” na terminalu.
Veoma interesantan detalj je poruka koja neposredno slijedi, a koju takodje emituje 5. proces:
Ja sam dijete (pid = 947), a moj roditelj je (pid = 1)
Roditelj procesa 947 bio je, kako znamo, 942, ali u prethodnoj poruci vidimo da je roditelj sada pid 1. Zasto? Pa, nemarni babo 942 je umro prije nego sto je sacekao da se djeca zavrse, tako da je nakon njegove smrti svu njegovu djecu naslijedio “pradedo” svih procesa, tzv. “init”, ciji je pid 1.
I tako svaki od procesa djece ispisuje svoju pricu na terminalu i umire, a brizni pradedo init redovno poziva wait za svu svoju djecu i svu praunucad koji su ostali bez babe.
Pitanje zasto kursor stoji na pocetku reda i zasto se ne pojavljuje shell prompt je ovim odgovoreno. Dakle, prompt se vec pojavio (kad je umro babo-proces), i shell ceka da ti uneses neku komandu. U medjuvremenu su djeca “svrljala” po terminalu, sto nije pod kontrolom shell-a, tj. shell ne zna da je neko pisao po terminalu i zato jos uvijek ceka da uneses neku komandu. Ako sada ponovo izvrsis svoj program, i kada se kursor pojavi na pocetku novog reda, uneses npr. ls, vidjeces da je prethodna tvrdnja tacna, dakle shell ce izvrsiti ls.
Put ka rjesenju …
Najprije je potrebno izbrisati prethodno navedeni exit, koji sprjecava roditeljski proces da saceka da se djeca zavrse, dakle:
for (i = 0; i < 5; i++)
printf("pid[%u] = %un", i, pid[i]);
for (i = 0; i < 5; i++)
waitpid(pid[i], NULL, 0);
Ako sada pokrenes program, vidjeces da sve mnogo bolje izgleda, osim …
Sve je super, roditelj ceka na djecu, djeca ispisuju dobar roditeljski pid, samo se na kraju pojavljuje poruka “Greska kod waitpid”. Razlog za to je cinjenica da su djeca terminirala, a babuka opet pokusava da ceka na njih:
for (i = 0; i < 5; i++)
waitpid(pid[i], NULL, 0);
/* roditelj opet ceka */
if (waitpid(pid[i], NULL, 0) < 0) {
printf("Greska kod waitpidn");
exit(-1);
}
Dakle, vidi se da su nakon prve petlje sva djeca “gotova”, a roditelj u drugoj petlji opet pokusava cekati na djecu (koja vise ne postoje) i waitpid “javlja” gresku. Prema tome, potrebno je izbaciti prvu petlju i gotovo:
/* Startovanje novog procesa sa fork() */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid[5];
int i;
for (i = 0; i < 5; i++)
if (!(pid[i] = fork()))
break;
else if (pid[i] < 0) {
perror("fork");
exit(-1);
}
switch (i) {
case 0:
printf("Proces 1 krenuon");
sleep(10);
printf("Proces 1 zavrsavan");
break;
case 1:
printf("Proces 2 krenuon");
sleep(8);
printf("Proces 2 zavrsavan");
break;
case 2:
printf("Proces 3 krenuon");
sleep(6);
printf("Proces 3 zavrsavan");
break;
case 3:
printf("Proces 4 krenuon");
sleep(4);
printf("Proces 4 zavrsavan");
break;
case 4:
printf("Proces 5 krenuon");
sleep(2);
printf("Proces 5 zavrsavan");
break;
default:
printf("Ja sam babo %u sa petoro djece:n", getpid());
for (i = 0; i < 5; i++)
printf("pid[%u] = %un", i, pid[i]);
for (i = 0; i < 5; i++)
if (waitpid(pid[i], NULL, 0) < 0) {
printf("Greska kod waitpidn");
exit(-1);
}
exit(0);
}
printf("Ja sam dijete (pid = %u), a moj roditelj je (pid = %u)n",
getpid(), getppid());
exit(0);
}
e sad moze i jedna kahva …