PDA

Visualizza la versione completa : [C] Fork e execl


topolino
03-02-2012, 22:26
Cosa stampa il seguente main?

int main (void) {
printf("The quick brown fox jumped over ");
fork();
printf("the lazy dogs\n");
return 0;
}

OUTPUT:
name@mname-Scrivania:/The quick brown fox jumped over the lazy dogs
name@mname-Scrivania:/ The quick brown fox jumped over the lazy dogs

Io questo output me lo sono spiegato cosi : il processo parte e stampa la prima printf dopo chiama la fork quindi creoa un processo figlio il padre finisce di stampare con la seconda printf e il figlio riparte e fa la stampa del primo e poi del secondo.

e questo?

int main (void) {
printf("The quick brown fox jumped over ");
execl("/bin/echo","echo","the","lazy","dogs.",NULL);
return 0;
}

OUTPUT:
name@mname-Scrivania:/ the lazy dogs

perche'?
Questo non me lo spiego il primo printf che fine fa? perche non lo esegue?

Chiedo aiuto perche' non riesco a capire a che serve e come funziona la chiamata di sistema execl. Sono bene accette delucidazioni sull'uso di questa.

ramy89
03-02-2012, 23:08
prova così:


fprintf(stderr,"The quick brown fox jumped over ");

Oppure:


printf("The quick brown fox jumped over ");
fflush(stdout);



Originariamente inviato da topolino
Questo non me lo spiego il primo printf che fine fa? perche non lo esegue?


Se il programma fosse una persona ragionerebbe così: "mi segno tutto quello che c'è da stampare da qualche parte e poi lo stampo tutto in una botta".

topolino
03-02-2012, 23:22
Grazie
Domani provo perchè ora ho spento linux.

Pero' l'biettivo di questo esercizio consisteva nel capire come agisce la fork e la execl.
La fork ovviamente si occupa di creare un processo figlio o un processo padre...

Mi sapreste per caso spiegare perchè fa quelle stampe?
Grazie ancora

ramy89
03-02-2012, 23:26
execl esegue un programma e puoi scegliere che argomenti passargli, in /bin c'è un programma che si chiama echo, che serve per stampare caratteri sul terminale.
Lo puoi eseguire anche da terminale:


echo "the" "lazy" "dogs"

Oppure:


/bin/echo "the" "lazy" "dogs"


Queste cose ancora non le ho fatte ma ho trovato una bella guida qui:
http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

PS: Il messaggio di prima l' ho editato mentre postavi.

topolino
05-02-2012, 12:55
Nessuno sa dirmi come mai delle diverse stampe?

ramy89
05-02-2012, 13:03
Te l' ho detto, è il programma echo che viene lanciato e stampa quelle stringhe :dottò:

MItaly
05-02-2012, 14:57
In entrambi i casi potrebbero succedere due cose, a seconda di come viene gestito il buffering su stdout.

Perché? Perché non è vero che printf stampa direttamente su schermo quello che le fornisci: essa va piuttosto a scrivere i dati in un buffer di output, per evitare di perdere tempo con tante piccole scritture; il buffer in questione viene svuotato in determinate circostanze in parte non specificate dallo standard (in genere quando è pieno, quando viene incontrato un ritorno a capo, quando viene richiesto dell'input all'utente, quando viene svuotato esplicitamente).

Quello che succede nel tuo caso è questo:
Primo esempio: la prima printf scrive nel buffer, che nel tuo caso è sufficientemente piccolo perché non venga scritto ancora niente su schermo; avviene la fork: il processo viene "clonato" - e con esso il buffer in scrittura; in ciascun processo viene poi chiamata la seconda printf; o all'interno di questa o alla chiusura del processo viene finalmente svuotato il buffer - in entrambi i processi, per cui il testo viene scritto interamente da entrambi i processi.
Nel primo caso potresti vedere sia:


The quick brown fox jumped over the lazy dogs
The quick brown fox jumped over the lazy dogs

Se invece si fosse svuotato il buffer prima della fork (o perché era particolarmente piccolo, o a seguito di una fflush(stdout)) il risultato sarebbe stato:


The quick brown fox jumped over the lazy dogs
the lazy dogs
perché al momento della fork il buffer sarebbe stato vuoto, per cui ciascun processo dopo la fork avrebbe stampato solo "the lazy dogs".

Nel secondo caso potresti vedere sia:


The quick brown fox jumped over the lazy dogs.

che:


the lazy dogs.
Perché? Stesso discorso: se il buffer viene svuotato prima della execl, allora la prima scritta viene stampata. Viene quindi richiamata execl, che rimpiazza il "contenuto" del processo corrente (salvo alcune cose) caricando in memoria echo con i parametri in questione. echo si occupa di stampare la scritta passata come argomento ed esce.
Se invece il buffer non viene svuotato prima della exec, allora il suo contenuto va perduto, dato che la exec rimpiazza codice e dati del processo corrente caricando in memoria l'eseguibile specificato.

Nota che tutto questo si applica ai buffer in usermode (come appunto quelli gestiti dalla libreria C), i buffer dei descrittori file UNIX invece dovrebbero essere conservati.

topolino
05-02-2012, 22:12
Beh direi ottima spiegazione Mitaly, quello che mi aspettavo di sapere.perfetto.Grazie

L'unico dubbio che mi è rimasto sull'utilizzo in generale della exec.
Di norma si dice che la exec accompagna sempre una fork, quindi la exec e utilizzata per specifare cosa far fare al processo appena creato dalla fork?
Qual'è l'utilita' in generale di utilizzare la exec?

Grazie ancora

MItaly
06-02-2012, 02:42
Originariamente inviato da topolino
L'unico dubbio che mi è rimasto sull'utilizzo in generale della exec.
Di norma si dice che la exec accompagna sempre una fork, quindi la exec e utilizzata per specifare cosa far fare al processo appena creato dalla fork?
Il concetto è quello. Dopo che tu hai clonato il processo corrente, ne sostituisci il "contenuto" (codice in esecuzione, dati in memoria, ...) con quello che vai ad eseguire.
La separazione tra fork ed exec consente:
- di fare fork() senza exec(), ovvero creare dei cloni del processo corrente, ma separati dal processo padre, cosa che può servire ad esempio in uno scenario di server di rete come alternativa al multithreading;
- di fare qualcosa tra la fork() e la exec() che rimane al nuovo processo - un esempio "classico" è chiudere uno dei file descriptor standard e redirigerlo su un altro file o su una pipe, in modo da redirigere standard input o standard output su file o pipe;
- di fare una exec() senza una fork() - se il tuo programma arriva al punto in cui ha finito di lavorare e deve semplicemente chiamare un altro programma, invece di creare un nuovo processo può lanciarlo all'interno del processo corrente; va detto però che questo uso non credo che sia particolarmente diffuso.

Nota che non è impossibile lavorare senza avere fork() ed exec() separate: in effetti, su Windows c'è solo la CreateProcess*, che è una "fork()+exec()" (crea un nuovo processo facendolo partire direttamente con l'eseguibile specificato), dato che la filosofia di Windows è più sul multithreading.
La fork senza exec è sostituita con il multithreading o con un nuovo processo + qualche metodo di IPC; la exec senza fork non esiste (ma non è molto utile). Il fare qualcosa tra la fork() e la exec() non ha equivalente, per le operazioni comuni però in genere ci sono metodi alternativi (non è un caso che la CreateProcess abbia una quantità di opzioni che rasenta il limite del ridicolo :D ).

* almeno a livello di API Win32, poi in realtà a livello di kernel mi pare ci siano anche separate per meglio supportare eventuali layer di compatibilità POSIX.

Loading