Valutazione 4.87/ 5 (100.00%) 5838 voti

Condividi:        

La wait() in C - per esperti

Per tutti i tuoi problemi Linux entra qui e risolvili!

Moderatori: gunter, zendune

La wait() in C - per esperti

Postdi Swalke » 12/12/04 16:46

Spero di poter postare questo messaggio in questa stanza!

Premetto che sono un principinante di C!

Ho un problema nell'utilizzo della wait().
Credo che la cosa sia dovuta al fatto che mi sfugge qualcosa sul comportamento della wait... ...ma non capisco cosa.
L'esercizio che devo fare richiede quanto segue:

1) Vi è un processo padre che crea un figlio con la fork()
2) Il padre si mette in attesa del figlio tramite wait()
3) Il figlio termina
4) Il padre prosegue e crea un altro figlio con la fork
5) Il padre invoca un'altra wait per attendere le fine di questo figlio.

Ora vi riporto il mio codice che non riesco a capire perchè, non effettua l'attesa sul secondo figlio. Il programma è semplicissimo e oltre a creare i figli come detto sopra, fa solo delle stampe a video. (ho messo anche dei commentini per farvi sbattere il meno possibile)

Codice: Seleziona tutto
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
   int id;   //variabili di servizio usate solo per recuperare
   int id1;//gli ID dei processi per distinguere padre da iglio.

   id=fork();
   
   if(id == 0)   //codice eseguido dal primo figlio.
   {
      id1=getpid();
      printf("ID= %d - Io sono il primo figlio!\n", id1);
      sleep(3);
      printf("Primo figlio terminato\n");
      exit(0); //Qui termina il primo figlio
   }
   
   /*Codice eseguito solo dal padre*/   
   id1=getpid();   //restituisce il proces id di chi lo invoca
   printf("ID= %d - Io sono il padre!\n", id1);
   printf("Attendo la fine del primo figlio!\n");
   wait();   //mette in attesa della fine di un figlio.
   
   id=fork();

   if(id == 0)   //codice eseguido dal secondo figlio.
   {
      id1=getpid();
      printf("ID= %d - Io sono il secondo figlio!\n", id1);
      sleep(3);
      printf("Secondo figlio terminato\n");
      exit(0);  //Qui termina il secondo figlio
   }
   
   /*Codice eseguito solo dal padre*/
   printf("ID= %d - Io sono il padre!\n", id1);
   printf("Attendo la fine del secondo figlio!\n");
   wait();   //mette in attesa della fine di un figlio.   
   printf("Padre terminato, Fine dell'esercizio!\n");   
   exit(0);
}


Se provate a farlo girare avrete che:
1) Parte il padre e parte il primo figlio
2) Il padre attende il primo figlio
3) Il primo figlio termina
4) Parte il secondo figlio
5) Termina il padre
6) Passati i 3 secondi della sleep termina il secondo figlio.

Vi prego aiutatemi! Non capisco perchè il padre non aspetta il secondo filglio!!!

Se vi serve ho anche il codice (non fatto da me) che funziona correttamente, ma io non riesco a capire perchè il mio non funziona!!! :cry:
Avatar utente
Swalke
Hardware Admin
 
Post: 820
Iscritto il: 26/10/01 01:00
Località: Milano

Sponsor
 

Postdi disgrazia » 12/12/04 19:27

Beh, io ho fatto girare il tuo programma così com'era:
Codice: Seleziona tutto
disgrazia@server:~/sos$ gcc -o swalke swalke.c
disgrazia@server:~/sos$ ./swalke
ID= 3860 - Io sono il padre!
Attendo la fine del primo figlio!
ID= 3861 - Io sono il primo figlio!
Primo figlio terminato
ID= 3860 - Io sono il padre!
Attendo la fine del secondo figlio!
ID= 3862 - Io sono il secondo figlio!
Secondo figlio terminato
Padre terminato, Fine dell'esercizio!

Direi che funziona tutto come dovrebbe... che sistema operativo usi?
disgrazia
Download Admin
 
Post: 708
Iscritto il: 08/07/02 22:16

Postdi Swalke » 12/12/04 20:43

disgrazia, è impossibile che il tuo output sia quello perchè infatti manca la stampa

"secondo figlio terminato"

che dovrebbe venirti stampata dopo che ti viene visualizzato il prompt!

Infatti il mio output è così:

Codice: Seleziona tutto
ID= 3139 - Io sono il primo figlio!
ID= 3138 - Io sono il padre!
Attendo la fine del primo figlio!
Primo figlio terminato
ID= 3140 - Io sono il secondo figlio!
ID= 3138 - Io sono il padre!
Attendo la fine del secondo figlio!
Padre terminato, Fine dell'esercizio!
[swalke@localhost Desktop]$ Secondo figlio terminato

Prova a farci caso!
Se così non fosse significa che il tuo compilatore si è mangiato l'istruzione che stampa "secondo figlio terminato".

Fammi sapere!

Andre
Avatar utente
Swalke
Hardware Admin
 
Post: 820
Iscritto il: 26/10/01 01:00
Località: Milano

Postdi Swalke » 12/12/04 20:45

...scusa ma nel messaggio precedente ho dimenticato di togliere il tag del codice e la parte finale del messaggi oè rimasta inglobata nell' Output del programma! :D
Avatar utente
Swalke
Hardware Admin
 
Post: 820
Iscritto il: 26/10/01 01:00
Località: Milano

Postdi pjfry » 12/12/04 21:22

guarda che l'ha stampato anche a disgrazia, solo prima...
Avatar utente
pjfry
Moderatore
 
Post: 8240
Iscritto il: 19/11/02 17:52
Località: terni

Postdi disgrazia » 12/12/04 21:56

prova a mettere un
Codice: Seleziona tutto
fflush(stdout);
dopo l'istruzione
Codice: Seleziona tutto
printf("Secondo figlio terminato\n");

è possibile che le istruzioni vengano eseguite nell'ordine corretto ma che i messaggi vengano visualizzati fuori ordine, tant'è che l'ultimo messaggio ti compare dopo il prompt.
disgrazia
Download Admin
 
Post: 708
Iscritto il: 08/07/02 22:16

Postdi Swalke » 13/12/04 01:15

Hai ragione pj!
Scusa disgrazia, non avevo visto bene il tuo output!

Comunque mettendo la fflush non mi cambia niente.

Tra l'altro, la stampa che mi compare dopo il prompt mi compare dopo 3 secondi che è comparso il prompt ovvero dopo la sllep di 3 secondi del secondo figlio.

Questo vuol dire che il prompt esce dopo la exit(0) del processo padre che avviene quando il figlio non è ancora terminato! Quindi c'è qualcosa che non va!

Sto programmando sotto Mandrake 10.0 (se può esservi utile)!

Vi prego aiutatemi!
Avatar utente
Swalke
Hardware Admin
 
Post: 820
Iscritto il: 26/10/01 01:00
Località: Milano

Postdi pjfry » 13/12/04 10:28

potresti provare a usare wait(id)... sempre che esista e che la fork restituisca al padre il pid del figlio, non mi ricordo :undecided:
Avatar utente
pjfry
Moderatore
 
Post: 8240
Iscritto il: 19/11/02 17:52
Località: terni

Postdi Swalke » 13/12/04 11:12

Nuove notizie.
Se al posto di wait() uso wait(NULL), funziona alla perfezione.
in effetti la wait come parametro vorrebbe un puntatore a intero.

Ma nei programmi precedenti ha sempre funzionato senza... ...e anche la prima wait di questo programma funziona senza!
...la seconda invece se non metto il NULL come parametro mi da errore!
Avatar utente
Swalke
Hardware Admin
 
Post: 820
Iscritto il: 26/10/01 01:00
Località: Milano

Postdi disgrazia » 13/12/04 15:19

In effetti anch'io ho sempre usato il solito wait(&status), più che altro mi sorprende che il compilatore non si lamenti quando chiami wait() senza parametri visto che la dichiarazione prevede il parametro.
disgrazia
Download Admin
 
Post: 708
Iscritto il: 08/07/02 22:16

Postdi Swalke » 13/12/04 19:11

In effetti la cosa sorprende anche me.
Ma forse in generale i parametri sono opzionali quando chiami una funzione con C!

Solo che la wait deve comunque assegnare il valore a una variabile status e quindi se non gliela metti evidentemente associa il valore a un'altra cosa a caso, che se ti va bene è una zona di memoria che può fare al caso della wait se ti va male no!

Infatti la mia prima wait() riusciva ma la seconda no e mi ritornava un -1!

Ovviamente prendetemi con le pinze perchè ancora sono un principiante con C!
Avatar utente
Swalke
Hardware Admin
 
Post: 820
Iscritto il: 26/10/01 01:00
Località: Milano

Postdi pjfry » 13/12/04 21:14

Swalke ha scritto:Ma forse in generale i parametri sono opzionali quando chiami una funzione con C!

decisamente no... magari un compilatore particolarmente permissivo ti ci mette un NULL se non metti nulla, ma una funzione va chiamata nel modo in cui è definita, per quanto ne so io...
ovviamente potrebbe essere definita in entrambi i modi, ma non credo :undecided:
Avatar utente
pjfry
Moderatore
 
Post: 8240
Iscritto il: 19/11/02 17:52
Località: terni

Postdi Swalke » 13/12/04 22:09

Quindi C è come java nel chiamare le funzioni?

Io di compilatore uso gcc.
Ma allora se è come dici tu dovrebbe darmi per forza errore se uso una wait senza parametro, invece non me lo da!!!
Avatar utente
Swalke
Hardware Admin
 
Post: 820
Iscritto il: 26/10/01 01:00
Località: Milano

Postdi pjfry » 13/12/04 22:40

Swalke ha scritto:Quindi C è come java nel chiamare le funzioni?

uff... ma che vi insegnano a scuola al giorno d'oggi? :roll: :lol:
in realtà in java (e in c++) esiste l'overloading delle funzioni (metodi, vabbè...) cioè puoi definire 2 funzioni con lo stesso nome ma con argomenti diversi.
in c pare sia illegale (pare... ho una tale confusione con tra i vari linguaggi che ho dovuto cercare su google e ho trovato questo :roll: ) quindi immagino sia il compilatore a metterci un NULL per farla funzionare...
Avatar utente
pjfry
Moderatore
 
Post: 8240
Iscritto il: 19/11/02 17:52
Località: terni

Postdi Swalke » 13/12/04 22:58

...bhe... ...il mio gcc il Null non ce lo mette da solo!
Avatar utente
Swalke
Hardware Admin
 
Post: 820
Iscritto il: 26/10/01 01:00
Località: Milano

Postdi pjfry » 13/12/04 23:04

è vero... fa solo finta di niente perchè non sa cosa fare...
stando a quanto dicono qui (non ho letto tutto ma spero di aver capito il giusto :roll: :D ) hai i warning disabilitati, e non hai incluso i giusti header... possibile?
Avatar utente
pjfry
Moderatore
 
Post: 8240
Iscritto il: 19/11/02 17:52
Località: terni

Postdi zello » 13/12/04 23:22

Codice: Seleziona tutto
[zello@zello zello]$ gcc -Wall wait.c
wait.c: In function `main':
wait.c:19: warning: implicit declaration of function `exit'
wait.c:26: warning: implicit declaration of function `wait'

Brutta cosa la declarazione implicita di funzioni, vero? Se fosse stata una convenzione di chiamata diversa da quella standard del c, ti sarebbe andato in crash tutto quanto.
Tecnicamente:
1) la convenzione c stabilisce che sia il chiamante a pulire lo stack
2) il chiamante non si aspetta che la funzione aspetti argomenti, quindi semplicemente la chiama, mettendo sullo stack l'indirizzo di ritorno e basta.
3) wait si aspetta di trovare l'indirizzo di un int sullo stack, e prova a scrivere a quell'indirizzo.
4) stranamente non crashi: probabilmente hai un indirizzo valido (ebp, lo stack frame precedente? una variabile locale non utilizzata?). Wait ritorna, probabilmente con un codice di errore
5) il chiamante non pulisce lo stack, perché non ha nulla da pulire.
Se fosse stata una convenzione mista c/pascal, molto usata in Windows, il __asm(ret 4) di wait ti avrebbe rovinato lo stack
Per inciso, comunque, da me funziona benissimo:
Codice: Seleziona tutto
[zello@zello zello]$ ./a.out
ID= 8053 - Io sono il primo figlio!
ID= 8052 - Io sono il padre!
Attendo la fine del primo figlio!
Primo figlio terminato
ID= 8056 - Io sono il secondo figlio!
ID= 8052 - Io sono il padre!
Attendo la fine del secondo figlio!
Secondo figlio terminato
Padre terminato, Fine dell'esercizio!
Il faut être toujours ivre. Tout est là : c'est l'unique question. Pour ne pas sentir l'horrible fardeau du Temps qui brise vos épaules et vous penche vers la terre,il faut vous enivrer sans trêve...
Avatar utente
zello
Moderatore
 
Post: 2351
Iscritto il: 06/05/02 13:44

Postdi pjfry » 13/12/04 23:38

ecco... io mi sbatto a cercare e poi arriva zello che sa tutto a memoria :aaah ;)
Avatar utente
pjfry
Moderatore
 
Post: 8240
Iscritto il: 19/11/02 17:52
Località: terni

Postdi zello » 13/12/04 23:41

no, zello non sa tutto a memoria.
zello dà un:
Codice: Seleziona tutto
[zello@zello zello]$ man 2 wait

e impara che gli headers e i prototipi sono
Codice: Seleziona tutto
WAIT(2)                    Linux Programmer's Manual                   WAIT(2)
NAME
       wait, waitpid - wait for process termination
SYNOPSIS
       #include <sys/types.h>
       #include <sys/wait.h>
       pid_t wait(int *status);
       pid_t waitpid(pid_t pid, int *status, int options);

e deduce che qualcuno, come peraltro avevate già detto, ha incluso gli headers errati...
Poi prova a capire perché la cosa non ha mandato a ramengo tutto quanto.
Il faut être toujours ivre. Tout est là : c'est l'unique question. Pour ne pas sentir l'horrible fardeau du Temps qui brise vos épaules et vous penche vers la terre,il faut vous enivrer sans trêve...
Avatar utente
zello
Moderatore
 
Post: 2351
Iscritto il: 06/05/02 13:44

Postdi pjfry » 13/12/04 23:55

zello ha scritto:no, zello non sa tutto a memoria.

si, a cercare gli headers su internet c'ero arrivato anch'io... ma tutta la spiegazione teorica dopo credo di essermela dimenticata 2 giorni dopo calcolatori elettronici :oops:
Avatar utente
pjfry
Moderatore
 
Post: 8240
Iscritto il: 19/11/02 17:52
Località: terni

Prossimo

Torna a Software Linux


Topic correlati a "La wait() in C - per esperti":


Chi c’è in linea

Visitano il forum: Nessuno e 5 ospiti