2014-11-03 10 views
5

Come si eliminano in modo sicuro oggetti C++ statici nel caso in cui più thread (Posix) chiamano in parallelo exit()?distruttori statici sicuri quando più thread chiamano exit()

Appare nel mio ambiente CentOS6 che exit() esegue atexit (o on_exit) funzioni di pulizia chiamando qualcosa come fct[--cnt]() dove cnt è il numero di gestori registrati. Quando più thread chiamano exit() allo stesso tempo, abbiamo una condizione di competizione nell'operazione --cnt10 non protetta e alcuni gestori possono essere saltati o richiamati più volte (causando l'arresto occasionale). Quindi, come posso assicurarmi che solo uno dei thread di chiamata exit() effettui la pulizia e tutti gli altri si fermino? Nota che inserire un pthread_mutex_lock() in un gestore di cleanup non aiuta perché questo gestore potrebbe essere saltato ...

Purtroppo non posso evitare che più thread chiamino exit() perché è il codice che i miei utenti scriveranno (sto fornendo un biblioteca a loro).

Alla ricerca di idee sicure, grazie!

+1

Di cosa ti preoccupi esattamente? Hai qualcosa nei tuoi oggetti allocati staticamente che DEVONO essere clenati (se sì cosa)? È generalmente sicuro di uscire senza ripulire in moderni SO sofisticati. Se si deve eseguire la pulizia, suggerirei che probabilmente è necessario trovare una soluzione migliore piuttosto che lasciare la chiamata al codice client di uscita, ad esempio implementare il codice in una libreria condivisa e utilizzare la funzione di pulizia della libreria condivisa per ripulire, forse ? Oppure documenta che "non devi chiamare' exit() ', usa' my_safe_exit() '", e poi fai riferimento a questo quando i clienti si lamentano che non funziona. –

+0

In aggiunta a quanto sopra, cosa succede se i client si bloccano (errore di stack, errore di segmentazione) o debug ed escono nel debugger senza chiamare exit? –

+0

Ho alcuni oggetti statici che C++ distruggerà, ma non possiamo farlo in sicurezza in parallelo (condizioni di competizione nei distruttori).Questa pulizia è necessaria, ad esempio, per chiudere correttamente i flussi di file di traccia, quindi la pulizia automatica dal sistema operativo non è un'opzione. – Rainer

risposta

0

Se stai usando gcc, è possibile utilizzare il codice sottostante per definire una procedura di pulizia:

void __attribute__ ((destructor)) my_fini(void); 

Se ciò non risolve il problema, come sulla definizione di un singolo oggetto con durata statica il cui distruttore si prenderà cura della tua pulizia?

1

Non esiste un modo portatile per gestire più chiamate a exit() - perché non è definito (comportamento) cosa succede in quel caso.

Tuttavia, per alcune piattaforme particolari è possibile trovare un modo per farlo. Una soluzione alquanto generica per "chiamate più volte" consiste nell'avere una bandiera nei propri oggetti statici come "Sono già stato distrutto". Come al solito, è possibile nasconderlo in un modello:

template <typename T> class StaticExitHandled { 
public: 
    std::unique_ptr<T> t_; 
    ~StaticExitHandled() { t_.release(); } 
}; 

Ora ricordarsi di dichiarare tutti gli oggetti statici con questo modello. Questo è solo il nocciolo di esso, aggiungi campane e fischietti secondo i tuoi gusti. Inoltre, invece di std :: unique_ptr <> puoi usare boost :: opzionale <> o qualcosa del genere.

Non penso ci sia una soluzione generica per "non chiamare affatto".

In realtà, vorrei sconsigliare di avere oggetti statici non banali in ambiente multi-thread. Quindi, solo i POD statici e gli oggetti con distruttori severamente limitati (a seconda di cosa è sicuro fare a questo punto nel proprio ambiente - vale a dire chiudere gli handle dei file è OK nella maggior parte degli ambienti).

Problemi correlati