Visualizzazione dei risultati da 1 a 7 su 7

Discussione: [C] waitpid

  1. #1
    Utente di HTML.it L'avatar di /dev/null
    Registrato dal
    May 2004
    Messaggi
    1,936

    [C] waitpid

    Non ci sto capendo più niente
    Sto facendo un programma che agisce in questo modo:
    si connette a internet e quando riceve una richiesta crea un figlio con la funzione fork, ed il padre continua ad accettare richieste...
    Come faccio però a vedere quando il figlio muore, senza far bloccare il padre?
    Ovviamente devo usare la funzione waitpid... Ma non ho ben capito come usarla...

    Mi completate questo pezzetto di codice per far sì che il padre riesca a trovare i figli defunti senza bloccarsi?

    codice:
    while ( 1 ) {
    	// ... attendo la connessione
    	
    	// creo il figlio
    	pid = fork();
    	
    	if ( pid < 0 ) {
    		printf ( "Impossibile creare un figlio: %s.\n", strerror ( pid ) );
    	}
    	
    	if ( pid  == 0 ) { // figlio
    		// ...
    	}
    	
    	// ora devo verificare la morte del figlio, ma come???
    }
    Ultima modifica ad opera dell'utente /dev/null il 01-01-0001 alle 00:00

  2. #2

    Re: [C] waitpid

    Originariamente inviato da /dev/null
    Non ci sto capendo più niente
    Sto facendo un programma che agisce in questo modo:
    si connette a internet e quando riceve una richiesta crea un figlio con la funzione fork, ed il padre continua ad accettare richieste...
    Alla morte del figlio, il padre deve intraprendere qualche azione particolare?

    Come faccio però a vedere quando il figlio muore, senza far bloccare il padre?
    O installi un signal handler o fai un giro di polling con waitpid.
    Potresti iniziare cosi` (attenzione: codice stilisticamente discutibile e non testato):

    codice:
    while ( 1 ) {
            pid_t child_pid
    	// ... attendo la connessione
    	
    	// creo il figlio
    	pid = fork();
    	
    	if ( pid < 0 ) {
    		printf ( "Impossibile creare un figlio: %s.\n", strerror ( pid ) );
    	}
    	
    	if ( pid  == 0 ) { // figlio
    		// ...
    	}
    	
    	// ora devo verificare la morte del figlio, ma come???
          
          do {
              child_pid = waitpid(-1, NULL, WNOHANG);
          } while (child_pid > 0);
          if (child_pid < 0) {
              perror ("waitpid");
          }
    }
    "Qualsiasi esperto ha paura di combattere usando la katana vera. Anch'io. Ma non ignoro la mia paura, riesco ad accettarla, e a metterla da parte accanto a me".

  3. #3
    metti un "wait(&pid)" quando sei nel processo padre...
    in modo tale che il padre aspetta la terminazione del figlio!
    pid è un intero che da il valore di ritorno della fork()!
    :rollo:
    ---------------------------------
    Programmatore C

  4. #4
    Utente di HTML.it L'avatar di Ed_Bunker
    Registrato dal
    Jul 2003
    Messaggi
    1,119
    Secondo me la cosa piu' semplice e' utilizzare la sigaction affinche'
    all'arrivo del segnale SIGCHLD (Ignorato per default) tu ti possa accorgere che il figlio e' terminato ed eventualmente intraprendere qualche azione particolare.

    Esempio:
    codice:
    int main *int argc, char * argv[])
    {
    ...
    struct sigaction new, old;
    new.sa_handler = miaGestione;
    sigaction(SICGCHLD, &new, &old);
    ...
    /*Adesso ogni volta che ricevi un SIGCHLD il controllo
    passera' alla rotuine 'miaGestione'*/
    }
    
    void miaGestione(int sig)
    {
    /*Qui fai quello che "vuoi"...*/
    }

  5. #5
    premetto che di c++ nn ne capisco quasi niente, però su uno dei lucidi che ho io relativo a sistemi operativi c'è questo codice che dovrebbe essere un esempio di shell semplificata
    codice:
    while (TRUE){
                 Read_command(command, parameters);
                 if (fork()!=0) {
                     waitpid(-1, &status, 0);
                 } else {
                     execve(command, parameters,NULL);
                   }
          }
    se nn vado errato quel -1 nella waitpid vuol dire che deve aspettare finche tutti i processi siano terminati. nn si potrebbe applicare una cosa del genere anche al tuo programma magari? la mia è solo una supposizione dato che nn ne capisco niente di c++...

  6. #6
    Utente di HTML.it L'avatar di Ed_Bunker
    Registrato dal
    Jul 2003
    Messaggi
    1,119
    Originariamente inviato da gogetassj4dp
    Il fatto e' che una shell esegue un comando per volta (A meno che tu non voglia lanciare comandi in background e avere la possibilita' di eseguire un nuovo comando mentre il precedente e' ancora in esecuzione...). Il server sopra invece deve lancira i figli e tornare ad accettare nuove richieste pertanto non si deve bloccare. In pratica occorre che padre e figlio siano asincroni.
    Almeno penso...

  7. #7
    Utente di HTML.it L'avatar di /dev/null
    Registrato dal
    May 2004
    Messaggi
    1,936
    Mi pare che mi sono spiegato un pò male...
    Rilevare la morte del figlio mi serve solo perchè non rimanga uno zombie...

    Non posso bloccare il padre con la wait o con la waitpid senza usare l'opzione WNOHANG perchè se lo blocco finchè il figlio non muore il server rimane inattivo...

    Se io uso un codice come il seguente (quello che sto usando attualmente)
    codice:
    while ( 1 ) {
    	fd2 = accept ( fd, (struct sockaddr *) &client, (socklen_t *) &sin_size );
    	
    	if ( fd2 == -1 ) {
    		printf( "accept() error: %s", strerror ( errno ) );
    		exit( -1 );
    	}
    	
    	pid = fork();
    	
    	if ( pid < 0 ) {
    		printf ( "Impossibile creare un figlio: %s.\n", strerror ( errno ) );
    	}
    	
    	if ( pid  == 0 ) { // figlio
    		close ( fd );
    		printf( "Connection received from %s, port: %d\n", inet_ntoa( client.sin_addr ), client.sin_port );
    		printf("New Process created for the Client\n");
    		HandleClient ( ); 
    	} /*else {*/
    	
    	rc_pid = waitpid( -1, &chld_state, WNOHANG);
    	printf ( "rimosso il cadavere %d\n", rc_pid );
    	
    	close ( fd2 );
    }
    Succede questo:
    quando il server riceve una richiesta crea un figlio e contolla che non ci siano figli morti (se li trova li rimuove, così non figurano più come zombie)...

    Il problema è che tra una connessione ed un altra rimane sempre un processo zombie perchè il padre potrà verificare la sua morte solo quando riceverà un'altra richiesta, ma allora il figlio che fa nascere per la seconda richiesta non lo potrà verificare finchè non riceve una terza richiesta e così via all'infinito...


    Non avevo pensato che la morte di un processo invia un segnale (grazie Ed_Bunker)
    Gestendo il segnale ho risolto il problema...
    Se può interessare a qualcuno il segnale lo gestisco con
    codice:
    void sigchld_handler(int sig) {
    	pid_t pid = waitpid(-1, NULL, WNOHANG);
    	printf("child %d\n",pid);
    	
    	if  ( pid < 0 ) {
    		if ( errno == ECHILD )
    			puts("errno=ECHILD");
    		error_exit("waitpid");
    	}
    	
    	if ( signal(SIGCHLD, sigchld_handler) == SIG_ERR )
    		error_exit("signal");
    }
    è sufficiente mettere nel main "signal(SIGCHLD, sigchld_handler)" e così ogni qual volta che muore un processo figlio il programma lo rileva e lo rimuove, così non rimane un morto vivente


    Grazie a tutti
    Ultima modifica ad opera dell'utente /dev/null il 01-01-0001 alle 00:00

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.