Qual è la differenza tra exit () e abort ()?


Risposte:


116

abort()esce dal programma senza chiamare le funzioni registrate utilizzando atexit()prima e senza prima chiamare i distruttori degli oggetti. exit()fa entrambi prima di uscire dal programma. Tuttavia, non chiama i distruttori per gli oggetti automatici. Così

A a;
void test() { 
    static A b;
    A c;
    exit(0);
}

Distruggerà ae bcorrettamente, ma non chiamerà distruttori di c. abort()non chiamerebbe distruttori di nessuno degli oggetti. Poiché ciò è sfortunato, lo standard C ++ descrive un meccanismo alternativo che garantisce la terminazione corretta:

Gli oggetti con durata di memorizzazione automatica vengono tutti distrutti in un programma la cui funzione main()non contiene oggetti automatici ed esegue la chiamata a exit(). Il controllo può essere trasferito direttamente a tale main()gettando un'eccezione che viene catturata main().

struct exit_exception { 
   int c; 
   exit_exception(int c):c(c) { } 
};

int main() {
    try {
        // put all code in here
    } catch(exit_exception& e) {
        exit(e.c);
    }
}

Invece di chiamare exit(), organizza throw exit_exception(exit_code);invece quel codice .


2
+1 perché, mentre Brian R. Bondy era bravo, hai sollevato il problema di abort / exit (non distruttore di oggetti stack chiamati) e hai offerto l'alternativa per un processo C ++ ad alta intensità di RAII.
Paercebal,

Stavo cercando un modo per uscire da un programma senza chiamare dtor e la tua risposta è proprio quello che stavo cercando! Grazie
acemtp,

Questo è perfettamente corretto, ovviamente, se in realtà importa che i tuoi distruttori automatici di oggetti non vengano chiamati :-)
Chris Huang-Leaver

Per quanto ne so, un'ulteriore differenza tra l'uscita e l'interruzione sarebbe che l'interruzione potrebbe (a seconda della configurazione del sistema operativo) portare alla generazione di un dump principale.
Dirk Herrmann,

33

abort invia un segnale SIGABRT, exit chiude semplicemente l'applicazione eseguendo la normale pulizia.

È possibile gestire un segnale di interruzione nel modo desiderato, ma il comportamento predefinito è chiudere anche l'applicazione con un codice di errore.

interruzione non eseguirà la distruzione oggetto del vostro statico e membri a livello mondiale, ma l'uscita volontà.

Naturalmente, quando l'applicazione è completamente chiusa, il sistema operativo libererà tutta la memoria non ordinata e altre risorse.

In entrambi abort e uscita terminazione del programma (supponendo che non si è ignorare il comportamento predefinito), il codice di ritorno sarà restituito al processo padre che ha avviato l'applicazione.

Vedi il seguente esempio:

SomeClassType someobject;

void myProgramIsTerminating1(void)
{
  cout<<"exit function 1"<<endl;
}

void myProgramIsTerminating2(void)
{
  cout<<"exit function 2"<<endl;
}

int main(int argc, char**argv)
{
  atexit (myProgramIsTerminating1);
  atexit (myProgramIsTerminating2);
  //abort();
  return 0;
}

Commenti:

  • Se l' interruzione non viene scomposta: non viene stampato nulla e il distruttore di qualche oggetto non verrà chiamato.

  • Se l' interruzione viene commentata come sopra: verrà chiamato someobject destructor otterrai il seguente output:

funzione di uscita 2
funzione di uscita 1


Qui, ha chiamato exit function 2 ALLORA exit function 1. gcc 4, Linux 2.6.
Strager

1
La pagina man di atexit dice: "Le funzioni [registrate usando atexit] sono chiamate in ordine inverso; non vengono passati argomenti."
Strager

@strager ha ragione, le funzioni registrate da atexit dovrebbero essere chiamate in ordine inverso quando viene chiamata exit o return principale.
Robert Gamble,

Ha eseguito un test e sembra che i distruttori delle istanze globali siano chiamati dopo tutti i callback atexit.
Strager

+1 per ricordare alle persone che il sistema operativo alla fine libererà tutte le risorse allocate anche dopo una chiamata abort ().
Fingolfin,

10

Le seguenti cose accadono quando un programma chiama exit():

  • Le funzioni registrate dalla atexitfunzione vengono eseguite
  • Tutti i flussi aperti vengono scaricati e chiusi, i file creati da tmpfilevengono rimossi
  • Il programma termina con il codice di uscita specificato per l'host

La abortfunzione () invia il SIGABRTsegnale al processo corrente, se non viene rilevato il programma viene chiuso senza alcuna garanzia che i flussi aperti vengano scaricati / chiusi o che i file temporanei creati tramite tmpfilevengano rimossi, atexitle funzioni registrate non vengano chiamate e un lo stato di uscita zero viene restituito all'host.


hmm. lo standard dice che il programma non viene chiuso solo se il gestore del segnale "non ritorna". stai abbastanza bene con C. riesci a immaginare qualche scenario che gli consentirebbe di continuare la normale esecuzione senza tornare? immagino longjmp, ma non sono sicuro di come si comporta nei gestori di segnali.
Johannes Schaub - litb

In generale, chiamare longjmp da un gestore di segnale non è definito, ma esiste un caso speciale per quando il segnale è stato generato con aumento / interruzione, quindi suppongo che ciò sarebbe teoricamente possibile, anche se non credo di averlo mai visto. Ora dovrò provarlo;)
Robert Gamble il

1
Questo sembra funzionare (suddiviso in più post a causa del limite di 300 caratteri): #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <setjmp.h> volatile sig_atomic_t do_abort = 1; jmp_buf env; void abort_handler (int i) {do_abort = 0; longjmp (env, 1);}
Robert Gamble,

int main (void) {setjmp (env); put ("A setjmp"); if (do_abort) {signal (SIGABRT, abort_handler); put ("Calling abort"); abort (); } put ("Didort abort!"); ritorna 0; }
Robert Gamble il

Su Ubuntu 7.04 questo stampa: A setjmp Chiamata abort A setjmp Non si è interrotta!
Robert Gamble,

5

Dalla pagina di manuale exit ():

La funzione exit () provoca la normale terminazione del processo e il valore di status & 0377 viene restituito al genitore.

Dalla pagina di manuale abort ():

Abort () prima sblocca il segnale SIGABRT, quindi genera quel segnale per il processo di chiamata. Ciò comporta l'interruzione anomala del processo a meno che il segnale SIGABRT non venga catturato e il gestore del segnale non ritorni.


4

abortinvia il SIGABRTsegnale. abortnon ritorna al chiamante. Il gestore predefinito per il SIGABRTsegnale chiude l'applicazione. stdioi flussi di file vengono scaricati, quindi chiusi. I distruttori per le istanze di classe C ++ non sono tuttavia (non sei sicuro su questo - forse i risultati non sono definiti?).

exitha i suoi callback, impostati con atexit. Se vengono specificati i callback (o solo uno), vengono chiamati nell'ordine inverso rispetto al loro ordine di registrazione (come uno stack), quindi il programma termina. Come con abort, exitnon ritorna al chiamante. stdioi flussi di file vengono scaricati, quindi chiusi. Inoltre, vengono chiamati i distruttori per le istanze di classe C ++.


exit può avere più funzioni di callback registrate tramite atexit, quando exit viene chiamato tutte le funzioni di callback verranno chiamate nell'ordine inverso in cui sono state registrate.
Robert Gamble,

@Gamble, certo, l'ho menzionato qualche minuto fa in un commento alla risposta di @ Bondy. Modificherò la mia risposta per riflettere quella.
Strager
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.