2013-05-13 8 views
5

Wenn ich verstehe, wie C++ - Compiler lokale Variablen handhaben, benötigt IsShutdownInProgress() keine Sperre, da die statische Variable shutdownInProgress auf dem Stapel abgelegt wird. Hab ich recht?Mutex beim Zurückgeben des Objektwerts

class MyClass 
{ 
    private: 
     // Irrelevant code commented away 
     static pthread_mutex_t mutex; 
     static bool shutdownInProgress; 
    public: 
     static void ShutdownIsInProgress() 
     { 
      pthread_mutex_lock(mutex); 
      shutdownInProgress = true;     
      pthread_mutex_unlock(mutex); 
     } 

     static bool IsShutdownInProgress() 
     { 
      // pthread_mutex_lock(mutex); 
      // pthread_mutex_unlock(mutex); 
      return shutdownInProgress; 
     } 
} 

Antwort

7

Bin ich nicht brauchen richtig?

Nein. Dies wird eine Kopie davon machen, um zurückzukehren; aber es zu lesen, um diese Kopie ohne Synchronisierung zu machen, wird ein Datenrennen, mit undefiniertem Verhalten geben.

static bool IsShutdownInProgress() 
{ 
    pthread_mutex_lock(mutex); 
    bool result = shutdownInProgress; 
    pthread_mutex_unlock(mutex); 
    return result; 
} 

oder unter Verwendung einer weniger fehleranfällig RAII Lock-Typ: Sie werden eine lokale Kopie davon mit der Mutex gesperrt machen müssen

static bool IsShutdownInProgress() 
{ 
    lock_guard lock(mutex); 
    return shutdownInProgress; 
} 

In C++ 11, können Sie Betrachten Sie std::atomic<bool> für bequemeren und vielleicht effizienteren Zugriff auf einfache Typen aus mehreren Threads.

1

Ja, es muss eine Sperre

C++ 11 Speicher-Modell besagt, Sie haben ein Daten Rennen wenn alle Threads Wert bei gleichzeitig einem anderen Thread zu lesen schreiben. Dies liegt daran, dass sowohl ein Lesen als auch ein Schreiben nicht atomar sein können.

In diesem Fall werden Sie ein lokales von der Funktion zurückgeben, aber um den lokalen zu erhalten, muss der Compiler den Wert in shutdownInProgress kopieren, der gleichzeitig von einem anderen Thread geändert werden kann, der ShutdownIsInProgress() aufruft.

Eine einfache Möglichkeit, dies zu lösen, ist shutdownInProgress ein Atom zu machen:

static std::atomic<bool> shutdownInProgress; 

Wenn Sie es atomar zu machen, müssen Sie alle Sperren überhaupt für beide Funktion

2

Race-Bedingungen haben nichts damit zu tun, ob sich eine Variable auf dem Heap oder auf dem Stack befindet. Eine Racebedingung ist, wenn ein Thread eine Variable (einen Speicherort) ändert und ein anderer Thread dieselbe Variable liest oder ändert. Es gibt keine Garantie, dass die Modifikation einer bool atomaren ist, so dass der gepostete Code eine Race Condition hat und daher undefiniertes Verhalten.

würde eine fix sein, den Wert des bool zu speichern, wenn der Mutex und gibt die variable gehalten wird:

static bool IsShutdownInProgress() 
{ 
    pthread_mutex_lock(&mutex); 
    bool result = shutdownInProgress; 
    pthread_mutex_unlock(&mutex); 
    return result; 
} 

C++ 11 std::mutex und std::lock_guard eingeführt, und die Verwendung des lock_guard verwendet werden könnten, würde das Erfordernis einer temporären variablen vermeiden bool Wert für die Rückkehr zu speichern:

static std::mutex mtx_; 
static bool IsShutdownInProgress() 
{ 
    std::lock_guard<std::mutex> lk(mtx_); 
    return shutdownInProgress; 
} 

C++ 11 auch std::atomic<> eingeführt, die sicherstellen würde m NDERUNG ist atomar und die Notwendigkeit für eine explizite Sperre vermeiden:

static std::atomic<bool> shutdownInProgress; 
static bool IsShutdownInProgress() 
{ 
    return shutdownInProgress; 
} 

Wenn C++ 11 nicht verfügbar ist, zu boost::atomic wurde in v1.53.0 eingeführt und steigern auch gleichwertige boost::mutex and boost::lock_guard.