[ Konstantin91 @ 19.07.2012. 00:49 ] @
Poceo sam da ucim Operativne sisteme 1 na VISER-u pa mi treba objasnjenje oko procesa i niti...

Procitao sam osnovno o OS, kapiram da vise nismo u periodu kada bi smo programe pisali u masinskom jeziku ili asembleru i preko busenih kartica ubacivali... Kapiram da je OS jedan veliki administrator, bla bla bla...

Procitao sam i osnovno o procesima, da su to programi u izvrsenju, imaju svoje resurse, jedinstvene oznake.... Ono sto me malo buni jesu deca procesi i niti.

Imam jedan primer iz knjige pa evo da ga prenesem ovde

Code:

#include <stdio.h>
main(int argc, char *argv[]) {

int pid;
pid=fork()   // ovde imamo poziv forka koji pravi novi proces a pid je jedinstveni broj svakog procesa koji sluzi za oznaku

if(pid==0)   // proces dete
{
   excelp ("/bin/ls", "ls", NULL);    // izvrsavanje necega
}

else
{
  wait(NULL);
/* proces dete je zavrsio svoje aktivnosti */
exit(); 


Koliko sam iz ovoga uspeo shvatiti ovde nakon fork-a roditelj ima jednu brojnu oznaku a dete drugu ( 0 u ovom slucaju) sto je i logicno. Sada roditelj ceka da dete izvrsi svoj zadatak (wait) i nakon toga roditelj nastavlja sa svojim zadatkom tj ide exit, cime se proces poslednjom naredbom zavrsava i unistava.....

Shvatio sam da proces roditelj i dete uglavnom dele resurse, adresni prostor, ali i da ne mora biti tako...

Ono sto mene zanima je da li ovo mogu posmatrati kao program i potprogram, znaci nakon zavrsetka potprograma i vracenih rezultata (mada to nije obavezno) glavni program nastavlja sa radom ???

Ako sam dobro razumeo ovde je proces dete nastao izvrsavanjem sistemskog poziva fork, da li to znaci da svaki novi proces zapravo nastaje kao dete nekog drugog procesa (sto bi znacilo da je pocetni i glavni proces roditelj zapravo neki sistemski proces ili neki pocetni korisnicki proces) i da nije moguce napraviti neki novi proces koji nece imati svog roditelja vec ce zapravo biti nov proces u pravom smisliu te reci ???


Sada deo o nitima. I taj sam deo procitao, da niti zapravo predstavljaju male potprograme sa jednostavnim (najcesce) zadacima i da sluze da prikazu kvazi paralelno izvrsavanje koje zapravo nije moguce na 1 cpu sa 1 jezgrom vec se konstantnim dodeljivanjem (svicovanjem) procesora izmedju procesa (ukoliko je proces vise nitni onda niti) dolazi do privida da je to paralelno izvrsavanje ???

Kako sam shvatio niti se stvaraju izvrsavanjem sistemskog poziva clone() i slicno kao procesi roditelj - dete mogu deliti memoriju pa me to dovodi do pitanja cemu potreba za nitima ako je sve moguce odraditi preko forka-a tj preko procesa dete ako znamo da proces roditelj moze da nasavi sa izvrsavanjem nezavisno i konkurentno sa procesom detetom (suprutno od gore navedenog primera) ???


Literatura iz koje ucim je knjiga Operativni sistemi , autor Borislav Djordjevic, Dragan Pleskonjic i Nemanja Macek i za sada sam tek zagrebao po knjizi, 60 od 500+ strana... Vecinu stvari sam shvatio ali ovde sam naveo, verujem, neka pocetnicka pitanja jer zelim shvatiti stvar u srzi a ne da ucim napamet, sablonski.... Nadam se da ce neko uspeti da mi objasni ono sto sam pitao i ukaze na eventualne nepravilnosti i greske koje sam mozda (verovatno) napravio....
[ maksvel @ 19.07.2012. 08:33 ] @
Citat:
Konstantin91:

Ako sam dobro razumeo ovde je proces dete nastao izvrsavanjem sistemskog poziva fork, da li to znaci da svaki novi proces zapravo nastaje kao dete nekog drugog procesa (sto bi znacilo da je pocetni i glavni proces roditelj zapravo neki sistemski proces ili neki pocetni korisnicki proces) i da nije moguce napraviti neki novi proces koji nece imati svog roditelja vec ce zapravo biti nov proces u pravom smisliu te reci ???

...
Kako sam shvatio niti se stvaraju izvrsavanjem sistemskog poziva clone() i slicno kao procesi roditelj - dete mogu deliti memoriju pa me to dovodi do pitanja cemu potreba za nitima ako je sve moguce odraditi preko forka-a tj preko procesa dete ako znamo da proces roditelj moze da nasavi sa izvrsavanjem nezavisno i konkurentno sa procesom detetom (suprutno od gore navedenog primera) ???

Da, svaki proces pod Linuksom ima roditelja, osim početnih. Kernel kreira init, a posle init kreira sve ostale.

fork je vrlo nalik clone, pogledaj o razlikama npr. ovde
Preko clone flag-ova se definiše šta će novostvoreni proces (ili nit) deliti.

[ djoka_l @ 19.07.2012. 10:06 ] @
Citat:
Koliko sam iz ovoga uspeo shvatiti ovde nakon fork-a roditelj ima jednu brojnu oznaku a dete drugu ( 0 u ovom slucaju) sto je i logicno. Sada roditelj ceka da dete izvrsi svoj zadatak (wait) i nakon toga roditelj nastavlja sa svojim zadatkom tj ide exit, cime se proces poslednjom naredbom zavrsava i unistava.....


Ovo nije baš tačno. Funkcija fork() vraća procesu roditelju PID procesa deteta, a nulu procesu detetu. Dakle, rezultat fork-a služi da program zna da li radi u procesu roditelju ili detetu. Svaki proces može da sazna svoj PID pozivom funkcije getpid() ili PID roditelja pozivom funkcije getppid().

Znači ono što nije tačno u tvojoj gornjoj izjavi je da se neka oznaka dobija posle fork() (PID roditelja postoji i pre fork-a) kao i to da je nula oznaka ili PID deteta.

Citat:
Shvatio sam da proces roditelj i dete uglavnom dele resurse, adresni prostor, ali i da ne mora biti tako...


Nije tačno. fork formira kopiju procesa roditelja (uz neke male izuzetke) i posle toga oba procesa nastavljaju svoj rad nezavizno jedan od drugoga. Sa druge strane thread (koji se dobija clone() funkcijom) deli (skoro) sve resurse procesa roditelja. Velika razlika! fork - ne deli skoro ništa, clone - deli skoro sve.

Citat:
Ono sto mene zanima je da li ovo mogu posmatrati kao program i potprogram, znaci nakon zavrsetka potprograma i vracenih rezultata (mada to nije obavezno) glavni program nastavlja sa radom ???


Ne može. Ovde se formiraju dva nezavisna toka programa. Kod poziva potprograma, tok pozivajućeg dela koda se prekida, prelazi se na kod potprograma, a nakon završetka potprograma, tok se vraća u glavni program. Kod fork/clone formira se proces koji radi nezavisno od glavnog programa, tj. istovremeno se izvršavaju i program roditelj i program dete. Kod fork-a čak nema ni komunikacije između roditelja i deteta (osim ako se ne isprogramira). Proces roditelj i proces dete mogu da komuniciraju putem slanja signala (funkcija kill() ), proces roditelj može da sačeka da se procesi deca završe (funkcijom wait) ali ne mora. Procesi deca mogu da postoje i ako se proces roditelj završi i obrnuto. Ovde, takođe, nema vraćanja rezultata. Jedini "rezultat" koji proces dete vrati je signal da je završio. Kod threadova, pošto se dele varijable, proces dete može direktno da promeni neke varijable, koje proces roditelj može da očita, ali to ni u kom slučaju ne liči na način na koji radi potprogram.

Citat:
Ako sam dobro razumeo ovde je proces dete nastao izvrsavanjem sistemskog poziva fork, da li to znaci da svaki novi proces zapravo nastaje kao dete nekog drugog procesa (sto bi znacilo da je pocetni i glavni proces roditelj zapravo neki sistemski proces ili neki pocetni korisnicki proces) i da nije moguce napraviti neki novi proces koji nece imati svog roditelja vec ce zapravo biti nov proces u pravom smisliu te reci ???


Svaki proces na unix/linux OS nastaje kao dete nekog drugog procesa, a prvi proces (PID=1) je proces init. Proces na *nix-u nastaje kao rezultat sistemskog poziva fork ili exec i to su jedina dva načina da se napravi proces (ako ne računamo threadove koji su nešto malo drugo). fork pravi duplikat pozivajućeg procesa dok exec zamenjuje pozivajući proces novim procesom.
U primeru koji si ti stavio vidi se kako se koriste fork i exec. Tako rade i shell programi u *nix sistemima.
Kada bi u nekom shell-u hteo da izlistaš sadržaj foldera, uradio bi ls i to bi bilo izvedeno baš na isti način kao što je u tvom malom primeru. Dakle, shell prvo napravi kopiju samog sebe sa fork, zatim u procesu roditelju sačeka da se dete završi, dok u detetu komandom exec izvrši "samoubistvo" tako što pozove ls. Kada se ls završi, shell nastavlja sa radom.
Sa druge strane, kada bi u *nix shell-u rekao "ls &" (oznaka & na kraju linije u shellu znači zahtev da se komanda izvrši u pozadini) izvršavanje bi bilo isto osim u procesu roditelju, koji ne bi pozvao funkciju wait() nego bi nastavio sa svojim poslom (očitavanjem ulaza sa tastature i obradom tog ulaza).
[ djoka_l @ 19.07.2012. 10:59 ] @
Napisao sam jedan primer:

Code (c):

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
int i, pid, r;

   for(i=0; i<10; i++) {
      pid=fork();
      if (pid == 0) break;//child
      printf("Created child: %d with pid: %d\n", i, pid); //parent
      srand(pid); //mix random generator
   }

   //child continues here, parent also, but after it created 10 children

   if(pid==0){
   //child's part of code
      sleep(r=(rand()&0x7)); //sleeps 0-7s emulating some work
      printf("Child %d: Hello World! (after %ds)\n", i, r);
      exit(EXIT_SUCCESS);
   }
   else {
   //parent's code
      printf("Parent: Hello World!\n");
   }

   wait(NULL);
   printf("All procesess finished!\n");

}
 


a evo i njegovog izlaza:

Code:

$ ./forktest
Created child: 0 with pid: 4756
Created child: 1 with pid: 2688
Created child: 2 with pid: 4736
Created child: 3 with pid: 2752
Child 3: Hello World! (after 0s)
Created child: 4 with pid: 4600
Created child: 5 with pid: 4192
Child 5: Hello World! (after 0s)
Created child: 6 with pid: 1780
Child 7: Hello World! (after 0s)
Created child: 7 with pid: 1684
Created child: 8 with pid: 3428
Created child: 9 with pid: 224
Parent: Hello World!
All procesess finished!
$ Child 1: Hello World! (after 2s)
Child 8: Hello World! (after 3s)
Child 2: Hello World! (after 4s)
Child 0: Hello World! (after 5s)
Child 9: Hello World! (after 5s)
Child 6: Hello World! (after 6s)
Child 4: Hello World! (after 7s)


Kao što se vidi parent proces se vrti u petlji i kreira 10 child procesa, onda ispiše "Parent: Hello World!", zatim sačeka da se child procesi završe, a onda ispiše krajnju poruku "All processes finished" i završi rad.
Sa druge strane, child procesi nešto rade nakon kreiranja (spavaju 0-7 sekundi), zatim se jave sa Hello World i završe rad.


EDIT: napravio sam grešku, umesto wait(NULL) koji čeka da se završi prvi od child procesa, trebalo je da stavim waitpid(-1, &status, 0) da sačeka sve child procese da se završe (treba mi i jedna int promenljiva "status")

[Ovu poruku je menjao djoka_l dana 19.07.2012. u 12:11 GMT+1]