2013-03-30 14 views
6

Ich habe vor kurzem gelernt, dass Compiler Ihren Code durch Umordnen von Anweisungen optimieren, und dass dies durch Barrieren gesteuert werden kann.Benötige ich einen Zaun oder eine Schranke oder etwas, wenn Mutex Locks/Unlocks tief in Funktionsaufrufen vergraben sind?

IIRC, macht einen Mutex Verriegeln eine Sperre, und ein Mutex Entriegeln macht auch eine Barriere, Code innerhalb des kritischen Abschnitts zu verhindern, immer aus.

So pthread_mutex_lock und pthread_mutex_unlock muss implizit diese "Hindernisse" sein. Was, wenn ich eine Klasse wie diese habe, die meinen Mutex umschließt?

class IMutex { 
public: 
    virtual void lock() = 0; 
    virtual void unlock() = 0; 
}; 

scheint es mir, weiß der Compiler nicht, dass ich rufe pthread_mutex_lock() innerhalb lock() und pthread_mutex_unlock() innerhalb unlock(), weil es weg alle virtual'd ist.

Führt dies zu Fehlern? Muss ich Barrieren irgendwie manuell festlegen?

+2

Ich denke, ein Funktionsaufruf wäre eine Barriere für den Compiler Moving Code. Wir verwenden Mutex's und fügen keine Barrieren hinzu. Es gibt Speicherbarrieren, die eine andere Sache sind. –

+0

oh, das macht Sinn. Vielen Dank! – Verdagon

+0

Ja, kein vernünftiger Compiler wird um einen virtuellen Funktionsaufruf herumordnen ... –

Antwort

6

Neuordnen Anweisungen wird auf verschiedenen Ebenen. Der offensichtlichste ist der Compiler und ein weniger offensichtlicher ist die CPU (die im laufenden Betrieb ist). Synchronisierungsfunktionen sind jedoch fast immer ein Zaun, der verhindert, dass Anweisungen vor und nach dem Zaun neu geordnet werden.

Also, wenn Ihre virtuelle lockpthread_mutex_*() Anrufe dann Ihre virtuellen Funktionen enthält einen Zaun.

So die kurze Antwort lautet: Nein, es wird nicht zu Fehlern führen.

Es besteht auch das flüchtige Schlüsselwort, das auf der Plattform je kann auch einen Zaun erzeugen. Die Verwendung der volatilen Schlüsselwörter macht es jedoch sehr viel schwieriger, diese Zäune zu erkennen, da Sie jedes Mal, wenn Sie eine Funktion oder Variable verwenden, die flüchtig ist, einen Zaun einführen. Der Rat ist also, dass Sie die Synchronisationsfunktionen der Plattform verwenden.

Das einzige Mal, wenn Sie sich bewusst von Zäunen sein müssen, ist, wenn Sie nicht Gleichzeitigkeit Objekte Synchronisation durchzuführen verwenden (wie eine bool anstelle eines Mutex verwenden).

+1

Ich würde flüchtige Datenelemente nicht empfehlen, da es möglicherweise einen Speicherzaun einführt, der wiederum aufgrund des "tatsächlichen" Mutex einen Datenrasenfehler verbergen kann einen anderen Fehler haben ... Verwenden Sie geeignete Synchronisationsfunktionen anstelle von volatilen. – ActiveTrayPrntrTagDataStrDrvr

+0

Dank @ActiveTrayPrntrTagDataStrDrvr Ich aktualisierte die Antwort, um Ihre Empfehlung aufzunehmen. – DevWouter