Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 12

Discussione: [C] Gestione SIGINT

  1. #1
    Utente di HTML.it
    Registrato dal
    Mar 2012
    Messaggi
    214

    [C] Gestione SIGINT

    Ciao a tutti ho un problema con la gestione del segnale che ho citato sopra con il mio server multithread. Dunque, il server deve terminare attendendo la terminazione di tutti i suoi thread quando riceve SIGINT.

    Ho dunque pensato di dover far ignorare a tutti i thread creati il suddetto segnale, in quanto è solo il master thread a doverlo gestire. Ho realizzato la maschera del main thread in questo modo:

    codice:
    sigset_t signal_set; 
    struct sigaction *act; 
    	
    	/*Tutti i segnali vengono mascherati.*/
    	if( (act = calloc(1, sizeof(struct sigaction)) ) == NULL)
    		return -1; 
    	
    	if( (sigfillset(&signal_set)) == -1){
    		perror("Sigfillset"); 
    		return -1; 
    		}
    	
    	if( (pthread_sigmask(SIG_SETMASK, &signal_set, NULL) ) == -1){
    		perror("Pthread_sigmask"); 
    		return -1; 
    		}
    		
    	memset(&act, sizeof(act), 0);
    	act->sa_handler = SIG_IGN;
    
    	if( ( sigaction(SIGQUIT, act, NULL) ) == -1 ){
    		perror("Sigaction"); 
    		return -1; 
    	}
    	
    	/*Vengono installati i gestori dei segnali*/
    	act->sa_handler = fun_sig; 
    	if( ( sigaction(SIGTERM, act, NULL)) == -1 ){
    		perror("Sigaction"); 
    		return -1; 
    	}
    	
    	if( ( sigaction(SIGINT, act, NULL)) == -1 ){
    		perror("Sigaction"); 
    		return -1; 
    	}
    	
    	/*Viene rimossa la maschera.*/
    	if( (sigemptyset(&signal_set) ) == -1){
    		perror("Sigemptyset"); 
    		return -1; 
    	}
    	
    	if( (pthread_sigmask(SIG_SETMASK, &signal_set, NULL)) == -1 ){
    		perror("Pthread_sigmask"); 
    		return -1;
    	}
    
    free(act);
    fun_sig è una funzione che mi imposta il valore di una variabile di tipo sig_atomic_t ad un valore diverso da 0 per farmi uscire da un ciclo infinito.
    codice:
     
    void fun_sig(){
      running = 1;  //var globale
    }
    il server riceve il segnale quando è in questa porzione di codice:
    codice:
     
    while(running){
       if ( accept() == -1 && errno == EINTR )
               continue; //rivaluto running, ho ricevuto il segnale
       else 
             pthread_create(); 
    }
    
    //Dovrà essere eseguito dopo la ricezione del segnale
    for(i=0;i<numtrhead;i++)
    pthread_join();
    Dunque, il segnale viene ricevuto, ma il ciclo con le join non viene mai eseguito, e non riesco a capire il perchè...Qualcuno potrebbe aiutarmi?

  2. #2
    Utente di HTML.it
    Registrato dal
    Sep 2012
    Messaggi
    707
    Non capisco perché questa complicazione... magari c'è una ragione che non conosco eh.

    Non bastava semplicemente:
    codice:
    void fun_sig()
    {
        running = 0;
    
        for (i = 0; i < numthread; i++)
            pthread_join(thread[i], NULL);
    
        exit(0);
    }
    
    int main()
    {
        ...
        signal(SIGINT, fun_sig);
        signal(SIGTERM, fun_sig);
        ...
    }

  3. #3
    Utente di HTML.it
    Registrato dal
    Mar 2012
    Messaggi
    214
    Io devo mascherare i segnali per "posticiparne" l'esecuzione quando avrò eseguito la prima porzione di codice, ovvero l'inizializzazione del server. Dunque mi creo una maschera che mi ignora il segnale, quando la rimuovo avrò installato il gestore che mi farà terminare il processo. La versione che hai scritto tu l'ho utilizzata, ma me l'hanno sconsigliata (senza una vera motivazione che sto ancora cercando...). Utilizzavo però un salto non locale per rientrare nel main e non eseguire di nuovo l'inizializzazione del server.

  4. #4
    Utente di HTML.it
    Registrato dal
    Sep 2012
    Messaggi
    707
    Originariamente inviato da Smoke666
    Io devo mascherare i segnali per "posticiparne" l'esecuzione quando avrò eseguito la prima porzione di codice, ovvero l'inizializzazione del server.
    A parte che non è chiaro perché tu stai facendo ciò, ti prego non dirmi che lo stai facendo un'altra volta per far funzionare un test case scritto male....

  5. #5
    Utente di HTML.it
    Registrato dal
    Mar 2012
    Messaggi
    214
    Nono, quella parte l'ho momentaneamente archiviata e mi sono rivolto a chi ha scritto il test, sto attendendo una sua risposta. Devo solo terminare il server in maniera pulita, attendendo che tutti i thread terminino. Dunque avevo pensato di mascherare il segnale per tutta la durata dell'inizializzazione, per poi eseguirlo successivamente. Cosa che non posso fare con signal(SIGINT, gestore) per un semplice motivo:

    codice:
    main(){
    signal(SIGINT, SIG_IGN); //non devo essere interrotto in questa fase
    init(); 
    signal(SIGINT, gestore); //ripristino il gestore per terminare. 
    }
    Così facendo se ricevessi un segnale durante l'esecuzione di "init", lo perderei, non ricevendo mai il segnale. Questa è una mia supposizione atta a giustificare il consiglio di evitare questa forma di gestione, ma sono lieto di essere smentito..



    Forse ho intuito dove ho commesso l'errore...La maschera non devo rimuoverla in quella funzione che ho scritto, ma alla fine dell'inizializzazione, giusto? Dunque schematicamente:

    maschero il segnale
    initi();
    rimuovo maschera

  6. #6
    Utente di HTML.it
    Registrato dal
    Sep 2012
    Messaggi
    707
    Originariamente inviato da Smoke666
    non devo essere interrotto in questa fase
    Ma perché non devi essere interrotto nella init scusa? Anzi devi essere interrotto.
    Immagina che stai avviando il server e poi appena lanciato il comando ti accorgi che non dovevi farlo e premi CTRL+C.
    Perché mai dovresti completare l'inizializzazione ignorando il CTRL+C?
    Io non ho mai visto un software che si comporta in questo modo. Cattura fin da subito i signali e poi nel sighandler vai a verificare cosa c'è o meno da de-inizializzare per poi uscire.

  7. #7
    Utente di HTML.it
    Registrato dal
    Mar 2012
    Messaggi
    214
    Ok allora ripristino la situazione inziale, quando utilizzavo signal. Un'altra domanda, i thread devono ignorare il segnale, giusto? Deve essere solo il main a riceverlo e casomai gestire i thread creati.

  8. #8
    Utente di HTML.it
    Registrato dal
    Sep 2012
    Messaggi
    707
    È già così, se installi l'handler con signal dalla main i thread continuano a funzionare anche dopo il segnale.
    Si interrompe solo il codice che era eseguito dalla main.

  9. #9
    Utente di HTML.it
    Registrato dal
    Mar 2012
    Messaggi
    214
    L'utilizzo di pthread_join non è signal safe, se utilizzassi un salto non locale per tornare ad eseguire il main dopo il segnale questo è lecito e safe? Intendo:

    codice:
    void main(){
    signal(SIGINT, gestore); 
        init(); 
       if(setjmp(env) == 0){
            serve(); 
       } 
      cleanup(); //qui ci metto join, chiusura socket, file descriptor, free varie e tutto il resto... 
    }
    
    void gestore(){
      //cambio variabile globali
      longjmp(env, 1);
    }

  10. #10
    Utente di HTML.it
    Registrato dal
    Sep 2012
    Messaggi
    707
    Originariamente inviato da Smoke666
    L'utilizzo di pthread_join non è signal safe
    Su questo hai ragione, ma senza fare nessun jmp puoi fare:
    codice:
    void gestore(int sig)
    {
        running = 0;    
        signal(SIGINT, SIG_DFL); //reimposti l'azione di default e riprendi l'esecuzione nella main
    }
    
    int main()
    {
        signal(SIGINT, gestore); 
        init(); 
        serve(); 
        cleanup();
    }

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 © 2025 vBulletin Solutions, Inc. All rights reserved.