2013-05-04 4 views
6

Nehmen wir an, ich habe die folgende Funktion.Muss ich ein flüchtiges Schlüsselwort verwenden, wenn ich eine Variable zwischen Mutexes deklariere und sie zurückgebe?

std::mutex mutex; 

int getNumber() 
{ 
    mutex.lock(); 
    int size = someVector.size(); 
    mutex.unlock(); 
    return size; 
} 

Ist dies ein Ort volatile Schlüsselwort zu verwenden, während Größe deklarieren? Wird die Rückgabewert-Optimierung oder etwas anderes diesen Code brechen, wenn ich nicht flüchtig benutze? Die Größe von someVector kann von jedem der zahlreichen Threads geändert werden, die das Programm hat, und es wird angenommen, dass nur ein Thread (außer Modifikatoren) getNumber() aufruft.

+2

Es gibt eine Erklärung der volatilen hier: http://StackOverflow.com/Questions/154551/volatile-vs-interlocked-vs-lock – Will

+5

@Will ich glaube nicht, dass die C# 'volatile' ist das gleiche wie die C++' volatile' (obwohl es in beiden Sprachen in dieser Situation nutzlos wäre). –

+1

Hoppla, ich habe nicht gesehen, dass diese Antwort für C++ war. Hier ist eine bessere Erklärung der volatilen: http://StackOverflow.com/Questions/72552/Why-does-Volatile-Exist – Will

Antwort

5

Sie haben nicht erwähnt, was der Typ der mutex Variable ist, aber unter der Annahme, dass es eine std::mutex (oder etwas ähnliches, um gegenseitigen Ausschluss zu gewährleisten) ist, wird der Compiler verhindert, eine Vielzahl von Optimierungen durchzuführen. Sie müssen sich also keine Gedanken über die Rückgabewertoptimierung oder eine andere Optimierung machen, die es ermöglicht, dass die size() Abfrage außerhalb des Mutexblocks ausgeführt wird.

Sobald jedoch die Mutex-Sperre aufgehoben wird, kann ein anderer wartender Thread auf den Vektor zugreifen und ihn möglicherweise mutieren, wodurch die Größe geändert wird. Nun ist die von Ihrer Funktion zurückgegebene Nummer veraltet. Wie Mats Petersson in seinem answer erwähnt, wenn das ein Problem ist, muss die Mutexsperre von dem Aufrufer von getNumber() erfasst werden, und gehalten werden, bis der Aufrufer das Ergebnis verwendet. Dadurch wird sichergestellt, dass sich die Größe des Vektors während der Operation nicht ändert.


expliziter Aufruf mutex::lock gefolgt von mutex::unlock wird schnell undurchführbar für kompliziertere Funktionen die Ausnahmen, mehr return-Anweisungen usw. Eine wesentlich einfachere Alternative ist std::lock_guard zu verwenden, um die Mutex-Sperre zu erwerben.

int getNumber() 
{ 
    std::lock_guard<std::mutex> l(mutex); // lock is acquired 
    int size = someVector.size(); 
    return size; 
} // lock is released automatically when l goes out of scope 
8

Nein. Aber bedenken Sie, dass die size möglicherweise nicht die tatsächliche Größe nach dem Mutex freigegeben wird.

Edit: Wenn Sie einige Arbeit, die auf size ist korrekt, müssen Sie die gesamte Aufgabe mit einem Mutex wickeln müssen.

+0

Die Funktion wird nur als Hinweis für jetzt verwendet, so dass Genauigkeit im Moment nicht wirklich benötigt wird . Danke für die Köpfe. – Etherealone

1

Flüchtige ist ein Schlüsselwort, das Sie den Compiler zu sagen, verwenden, um buchstäblich tatsächlich zu schreiben oder die Variable lesen und keine Optimierungen anzuwenden. Hier ist ein Beispiel

int example_function() { 
int a; 
volatile int b; 
a = 1; // this is ignored because nothing reads it before it is assigned again 
a = 2; // same here 
a = 3; // this is the last one, so a write takes place 
b = 1; // b gets written here, because b is volatile 
b = 2; // and again 
b = 3; // and again 
return a + b; 
} 

Was ist der wirkliche Nutzen davon? Ich habe es in Delay-Funktionen gesehen (halten Sie die CPU für ein bisschen beschäftigt, indem Sie es zu einer Zahl zählen lassen) und in Systemen, wo mehrere Threads die gleiche Variable betrachten könnten. Es kann manchmal ein wenig mit Multi-Threading-Sachen helfen, aber es ist nicht wirklich ein Threading-Ding und ist sicherlich kein Wundermittel

Verwandte Themen