2012-07-25 18 views
5

Nel tentativo di creare una classe contenitore sicura da thread da zero, ho riscontrato il problema della restituzione dei valori dai metodi di accesso. Per esempio in Windows:Sezioni critiche e valori restituiti in C++

myNode getSomeData() 
{ 
    EnterCriticalSection(& myCritSec); 
    myNode retobj; 
    // fill retobj with data from structure 
    LeaveCriticalSection(& myCritSec); 
    return retobj; 
} 

Ora suppongo che questo tipo di metodo non è affatto thread-safe perché dopo il codice rilascia la sezione critica un altro thread è in grado di venire avanti e subito sovrascrivere retobj prima del primo filo ritorna. Quindi, qual è un modo elegante per restituire retobj al chiamante in modalità thread-safe?

+1

Ma retobj viene memorizzato nello stack? A meno che non sia dichiarato 'statico' non dovresti avere problemi con la sovrascrittura dei dati copiati. –

+0

A meno che qualcosa di strano stia accadendo, 'retobj' dovrebbe essere in pila, e ogni thread dovrebbe avere il proprio stack. Le condizioni di gara di questo tipo sono più comuni quando si lavora con memoria pre-allocata e si deve bloccare l'accesso per impedire la condivisione. – ssube

+0

@inface, ok buon punto, quindi fintanto che il valore di ritorno è memorizzato nello stack, sto bene. – ThomasMcLeod

risposta

7

No, è thread-safe perché ogni thread ha il proprio stack, ed è qui che lo è retobj.

Tuttavia, non è certamente sicuro per le eccezioni. Avvolgere la sezione critica in un oggetto in stile RAII potrebbe essere d'aiuto. Qualcosa di simile ...

class CriticalLock : boost::noncopyable { 
    CriticalSection &section; 

public: 
    CriticalLock(CriticalSection &cs) : section(cs) 
    { 
    EnterCriticalSection(section); 
    } 

    ~CriticalLock() 
    { 
    LeaveCriticalSection(section); 
    } 
}; 

Usage:

myNode getSomeData() 
{ 
    CriticalLock lock(myCritSec); // automatically released. 
    ... 
} 
2

Questo è C++ e retobj ha un tipo di archiviazione automatico, quindi è archiviato nello stack.

Ogni thread ha il proprio stack, quindi un altro thread non può eliminare il valore di retobj prima che venga restituito.