Pagina 1 di 1

esercizio fork()

MessaggioInviato: 29 gen 2019, 21:31
da marc96
Sono alle prese con il seguente esercizio sulla fork():
Codice: Seleziona tutto
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(){
  int ret1=0,ret2=0,ret3=0;
  printf ("[%d],%d,%d,%d\n", getpid (),ret1,ret2,ret3);
  (ret1=fork()) && (ret2=fork()) || (ret3=fork());
  wait();
  printf ("[%d],%d,%d,%d\n", getpid (), ret1, ret2, ret3);
}


Ho eseguito su due compilatori online:
su onlinegdb.com
ho come risposta
[5],0,0,0
[8],6,0,0
[7],6,0,8
[5],6,7,0
[9],0,0,0
[6],0,0,9

Mentre su ideone.com
ho come risposta
[15201],0,0,0
[15344],15342,0,0
[15201],0,0,0
[15343],15342,0,15344
[15201],0,0,0
[15201],15342,15343,0
[15201],0,0,0
[15345],0,0,0
[15201],0,0,0
[15342],0,0,15345

Quindi 6 stampe contro 10.
Guardando bene, nell'out di ideone.com si ripetono ben 4 out identici
[15201],0,0,0
che secondo me non ci dovrebbero stare, almeno credo, in quanto si riferiscono al processo padre iniziale.
Il resto dell'out lo comprendo (permette di capire come i diversi processi vengono eseguiti temporalmente) e i due compilatori forniscono lo stesso risultato, a parte l'id dei processi.
Ho eseguito più volte e l'out è risultato sempre lo stesso.

Avete una spiegazione per questi 4 out [15201],0,0,0 che non riesco a capire?
Grazie.

Re: esercizio fork()

MessaggioInviato: 29 gen 2019, 21:36
da rugweri
Il codice va messo entro i tag [code]: il regolamento lo prevede, e tra l'altro è assurdo (e, permettimi, anche un po' maleducato) aspettarsi che qualcuno legga del codice non formattato.

Re: esercizio fork()

MessaggioInviato: 29 gen 2019, 21:41
da marc96
Mi scuso, spero di aver modificato bene.

Re: esercizio fork()

MessaggioInviato: 29 gen 2019, 23:16
da xyz
Trascurando la pessima formattazione del codice, quel codice ha poco senso. In C le operazione booleane sono ottimizzate dal compilatore compresa la sequenza di valutazione e come è scritta dipende molto dalla velocità con cui lo scheduler risponde e su come assegna i processi in base al hardware disponibile.

La funzione "wait" senza parametro non sono riuscito a trovarla (Linux kernel 4.18.17) quindi il linker molto probabilmente utilizza la funzione con un parametro il quale è indeterminato. Se si aggiunge l'include "sys/wait.h" il compilatore segnala giustamente l'errore per la mancanza del parametro.

Re: esercizio fork()

MessaggioInviato: 30 gen 2019, 0:09
da marc96
Innanzitutto grazie per la risposta.
Che il codice non abbia senso è sicuro, ma chiedilo a chi assegna questi esercizi in una università italiana. Per fortuna non sono lo studente interessato (Ho da troppi anni superato quel periodo...)
Hai ragione sulla wait() senza argomento: a parte il fatto di come mai compilava senza l'include, ho inserito io questa funzione perché, usando la fork(),mi stabilizza l'out...(mi posso pure sbagliare). Ho trovato in rete anche wait(NULL).
Comunque ho ricompilato come mi suggerisci
Codice: Seleziona tutto
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
    int ret1=0,ret2=0,ret3=0, status;
    printf ("[%d],%d,%d,%d\n", getpid (),ret1,ret2,ret3);
    (ret1=fork()) && (ret2=fork()) || (ret3=fork());
    wait(&status);
    printf ("[%d],%d,%d,%d\n", getpid (), ret1, ret2, ret3);
}

Spero che la formattazione automatica di codeblocks sia accettabile, non so fare di meglio e non programmo da tanto tempo.
L'out però non è cambiato in entrambi gli ambienti e il dubbio iniziale rimane.

Re: esercizio fork()

MessaggioInviato: 30 gen 2019, 2:05
da xyz
Sorgente compilato col GCC con opzione di ottimizzazione "-O2".

L'output diretto:

Codice: Seleziona tutto
$> ./a.out
[6729],0,0,0
[6732],0,0,0
[6733],6730,0,0
[6730],0,0,6732
[6731],6730,0,6733
[6729],6730,6731,0

Se viene messo in pipe con un altro processo:

Codice: Seleziona tutto
$> ./a.out | tee
[6767],0,0,0
[6771],0,0,0
[6767],0,0,0
[6772],6769,0,0
[6767],0,0,0
[6769],0,0,6771
[6767],0,0,0
[6770],6769,0,6772
[6767],0,0,0
[6767],6769,6770,0

La pipe crea dei buffer temporanei per lo stdin e stdout per sincronizzare output.

Se si disattivano i buffer le cose ritornano come nel primo esempio:

Codice: Seleziona tutto
$> unbuffer ./a.out | tee
[7836],0,0,0
[7844],0,0,0
[7845],7842,0,0
[7842],0,0,7844
[7843],7842,0,7845
[7836],7842,7843,0


Ordine delle righe può cambiare in base al carico della CPU nel momento dell'esecuzione del comando.

P.S. Qui viene spiegato cosa succede quando si valuta l'espressione booleana con i valori di ritorno della fork:

https://www.geeksforgeeks.org/fork-and-binary-tree/

Re: esercizio fork()

MessaggioInviato: 30 gen 2019, 9:54
da marc96
grazie, sei gentilissimo. studio...