2015-05-01 6 views

risposta

8

Basta scrivere una guardia che utilizza il distruttore per la pulizia:

struct Guard { 
    CriticalSection& cs; 
    Guard(CriticalSection& cs) 
    : cs(cs) 
    { 
    EnterCriticalSection(cs); 
    } 
    ~Guard() { 
    LeaveCriticalSection(cs); 
    } 
    Guard(const Guard&) = delete; 
    Guard& operator = (const Guard&) = delete; 
}; 

Usage:

void f() { 
    Guard guard(cs); 
    ... 
} 
7

Usa Raii (Resource acquisizione è di inizializzazione) idioma:

struct GuardCS { 
    GuardCS(CRITICAL_SECTION& p_cs) : cs(p_cs){ 
     EnterCriticalSection(&cs); 
    } 
    ~GuardCS() { 
     LeaveCriticalSection(&cs); 
    } 
private: 
    // Protect against copying, remove: =delete on pre c++11 compilers 
    GuardCS(GuardCS const &) = delete; 
    GuardCS& operator =(GuardCS const &) = delete; 
    CRITICAL_SECTION& cs; 
}; 

Se stanno usando MFC per caso ci sono classi che astraggono tali cose: is Ccriticalsection usable in production?

+0

se potevo fare un suggerimento minore, e forse è ancora saggio omettere semplicemente per il gusto di un esempio più semplice su cui costruire, potrebbe essere in buona salute per fare GuardCS noncopyable. –

+1

@ come ho aggiornato – marcinj

3

"Come posso garantire che venga richiamata la funzione LeaveCriticalSection anche se viene generata un'eccezione?"

È possibile scrivere una piccola classe di supporto in questo modo:

class CsLocker { 
public: 
    CsLocker(CriticalSection& cs) 
    : cs_(cs) { 
     EnterCriticalSection(&cs_); 
    } 
    ~CsLocker() { 
      LeaveCriticalSection(&cs); 
    } 
    CsLocker(const CsLocker&) = delete; 
    CsLocker& operator=(const CsLocker&) = delete; 
private: 
    CriticalSection& cs_; 
}; 

che garantiranno che la sezione critica è sbloccato quando (e perché mai) il campo di applicazione è di sinistra.

+0

Questo è pericoloso. Se qualcuno copia accidentalmente il 'CsLocker', tu sei protetto. –

+0

@LightningRacisinObrit Hai ragione, l'ho risolto. –

3

Ti suggerisco di non utilizzare le sezioni critiche di WinAPI. È possibile ottenere lo stesso utilizzando std::mutex. Quando lo si utilizza, è anche possibile utilizzare il wrapper RAII idiom per il mutex di sblocco automatico (std::lock_guard).

AGGIORNAMENTO: una differenza tra la sezione critica e il mutex è che è possibile bloccare la sezione critica più volte su un thread, ma ciò non è vero per il semplice std :: mutex. Se avete bisogno di un comportamento ricorsivo di bloccare l'uso std::recursive_mutexstd::lock_guard<std::recursive_mutex>

UPDATE 2: dettagliata differenza tra le sezioni critiche e mutex sono descritti here, confronto delle prestazioni è here.

Motivi: è preferibile utilizzare un meccanismo definito standard ogni volta che è possibile. Se usi una cosa specifica per la piattaforma, avvolgila. Quindi, se hai paura delle prestazioni, crea una classe di sezione critica con i metodi di blocco/sblocco (per soddisfare i requisiti di concetto BasicLocakable) e usa std::lock_guard<MyCriticalSection>.

+0

Perché non dovrei usare le sezioni critiche di WinAPI? – Nick

+0

@Nick Perché il tuo codice non sarà trasferibile su altri sistemi. –

+0

Si limita il codice per l'esecuzione su sistemi solo per Windows senza motivi specifici. –

1

Le altre risposte sono corrette sull'utilizzo di oggetti RAII ma ritengo che valga la pena indicare un modo semplice per farlo con Boost.ScopeExit.

#include <boost/scope_exit.hpp> 
... 
EnterCriticalSection(&cs); 
BOOST_SCOPE_EXIT(&cs) { 
     LeaveCriticalSection(&cs); 
} BOOST_SCOPE_EXIT_END 
// code that may throw an exception