2009-06-09 10 views
6

Va bene registrare WSACleanup tramite la funzione atExit? Abbiamo diverse applicazioni che possono terminare in diversi punti del codice, quindi vorremmo evitare di mettere WSACleanup ovunque attraverso il codice. Chiamiamo in modo efficiente WSAStartup/WSACleanup tramite DllMain poiché abbiamo una dll che viene utilizzata da tutte queste applicazioni. Tuttavia, Microsoft consiglia severamente l'utilizzo di WSAStartup/WSACleanup tramite DllMain poiché ciò può causare deadlock. Possiamo spostare WSAStarup da DllMain e richiamarlo in un punto del codice per tutte le applicazioni prima che accedano alla libreria di socket di Windows. E, non appena chiamiamo WSAStartup, vorremmo utilizzare la funzione atExit per registrare una chiamata a WSACleanup. Qualcuno ha qualche esperienza con questo approccio? Grazie!WSACleanup e atExit

risposta

4

Se si dispone di un'app multi-thread e alcuni thread sono ancora connessi, le applicazioni all'altra estremità potrebbero non gradire il modo in cui la connessione viene interrotta. Quindi è preferibile chiudere tutte le comunicazioni in modo ordinato prima che main() termini e, quando lo hai fatto, puoi anche chiamare WSACleanup.

1

Beh, penso che Exit non dovrebbe essere usato. Dovresti seguire il principio RAII del wrapping dell'inizializzazione e della distruzione della libreria socket in una classe.

+0

Mentre il buono stile, questo non aiuta una virgola. Da un punto di vista del processo, l'elaborazione atexit() avviene nello stesso momento dell'esecuzione di distruttori globali. Qualsiasi problema avresti con la chiamata a WSACleanup da AtExit, probabilmente lo avresti ancora chiamato da un dtor. – MSalters

2

Concordo sul fatto che l'approccio RAII sia favorevole.

Tuttavia, una parola di avviso: atExit mescolato con DLL e maniglie è rotto su Windows. Sfortunatamente questo ha anche effetti RAII poiché questo è implementato con i gestori atExit dal runtime C++.

L'ordine che atexit gestori vengono chiamati finestre:

  1. uscita qualche parte è chiamata o principale() passa nell'ambito
  2. movimentatori AtExit definite nel processo sono chiamati.
  3. tutte le maniglie sono distrutte.
  4. Sono chiamati i gestori di atexit definiti in DLL.

Non importa se i gestori di atexit nelle DLL vengono registrati prima dei gestori nel processo, i gestori del processo vengono chiamati per primi e gli handle vengono distrutti prima che vengano chiamati i gestori di dll. Ciò si traduce in eccezioni win32, quando viene chiamato il codice di pulizia in quanto tutti gli handle di proprietà di DLL non sono più validi.

Questo codice di effetti che mantiene gli handle su thread, mutex, file, socket ecc. Se sono allocati in una dll, devono essere ripuliti prima che l'uscita venga chiamata o non del tutto.

A proposito, io non sono anti finestre, se sbaglio o qualcuno sa come aggirare questo mi piacerebbe sapere come questo mi provoca dolore indicibile nella pulizia delle applicazioni. Ho capito che stavo eseguendo il debug della gestione degli exit nel runtime C++, dopo aver ottenuto le eccezioni win32 all'uscita delle applicazioni.

Ho dovuto rimuovere tutte le chiamate per uscire dal mio codice. Ora ho assicurato che nessun dato statico in una DLL controlla un handle. Tutte le maniglie statiche sono controllate da oggetti che vengono distrutti quando il main esce dal campo di applicazione.

+1

Non rotto. Se si scaricavano le DLL prima dei dCI globali dall'EXE, ogni attore dall'applicazione non funzionava quando chiamava una funzione da quel dtor.La configurazione corrente consente all'EXE di dipendere dalle DLL, ma non viceversa. Inoltre, non aprire o chiudere gli handle in DLLMain, questa non è una nuova regola. L'elaborazione AtExit fa parte di DLLMain, quindi eredita tali regole. Una soluzione rapida consiste nell'utilizzare puntatori intelligenti per tutte le risorse DLL. Quando l'applicazione ripulisce il suo ultimo puntatore intelligente su una risorsa DLL, la DLL saprà che è in grado di ripulire, e questo è prima di AtExit. – MSalters

+0

Grazie per la nota su DLLMain, non me ne sono reso conto. La tua nota sul puntatore intelligente: funziona solo se è dichiarato in main o below e non statico, giusto? – iain

+0

Ancora non ho il modo corretto di farlo. Cosa succede se ho una DLL che fornisce una certa funzionalità. Un'applicazione che carica la DLL e richiama determinate funzioni (che accede internamente all'API Winsock) deve avere WSAStartup chiamato almeno una volta. Posso avvolgere tutte queste funzioni in una classe e assicurarmi che WSAStartup venga chiamato almeno una volta. L'applicazione ora può uscire in qualsiasi momento e l'unico modo che vedo di chiamare WSACleanup è a) tramite atExit o b) attraverso un descrittore globale. Da quello che ho capito, entrambi possono causare problemi. Qual è la via d'uscita? –

Problemi correlati