2009-09-24 4 views
9

Ich machte einen sehr einfachen Spinlock mit den Interlocked-Funktionen in Windows und testete es auf einer Dual-Core-CPU (zwei Threads, die eine Variable inkrementieren);Intel Inspector meldet ein Datenrennen in meiner Spinlock-Implementierung

Das Programm scheint gut zu funktionieren (es gibt das gleiche Ergebnis jedes Mal, was nicht der Fall ist, wenn keine Synchronisation verwendet wird), aber Intel Parallel Inspector sagt, dass es eine Race-Bedingung + bei Wert = j (siehe Code unten). Die Warnung verschwindet, wenn kritische Abschnitte anstelle meines SpinLocks verwendet werden.

Ist meine Implementierung von SpinLock korrekt oder nicht? Es ist wirklich seltsam, denn alle verwendeten Operationen sind atomar und haben die richtigen Speicherbarrieren und es sollte nicht zu Rennbedingungen führen.

class SpinLock 
{ 
    int *lockValue; 
    SpinLock(int *value) : lockValue(value) { } 

    void Lock() { 
     while(InterlockedCompareExchange((volatile LONG*)lockValue, 1, 0) != 0) { 
      WaitABit(); 
     } 
    } 

    void Unlock() { InterlockedExchange((volatile LONG*)lockValue, 0); } 
}; 

Das Testprogramm:

static const int THREADS = 2; 
HANDLE completedEvents[THREADS]; 
int value = 0; 
int lock = 0; // Global. 

DWORD WINAPI TestThread(void *param) { 
    HANDLE completed = (HANDLE)param; 
    SpinLock testLock(&lock); 

    for(int i = 0;i < 1000*20; i++) { 
     for(int j = 0;j < 10*10; j++) { 
      // Add something to the variable. 
      testLock.Lock(); 
      value += j; 
      testLock.Unlock(); 
     } 
    } 
    SetEvent(completed); 
} 

int main() { 
    for(int i = 0; i < THREADS; i++) { 
     completedEvents[i] = CreateEvent(NULL, true, false, NULL); 
    } 
    for(int i = 0; i < THREADS; i++) { 
     DWORD id; 
     CreateThread(NULL, 0, TestThread, completedEvents[i], 0, &id); 
    } 

    WaitForMultipleObjects(THREADS, completedEvents, true, INFINITE); 
    cout<<value; 
} 

Antwort

4

Parallel Dokumentation des Inspektors für data race schlägt einen kritischen Abschnitt oder ein Mutex um Rennen unter Windows zu reparieren. Nichts deutet darauf hin, dass Parallel Inspector weiß, wie man einen anderen Schließmechanismus erkennt.

Werkzeuge zur Analyse neuartiger Verriegelungsmechanismen neigen dazu, statische Werkzeuge zu sein, die jeden möglichen Pfad durch den Code betrachten. Die Dokumentation von Parallel Inspector impliziert, dass der Code einmal ausgeführt wird.

Wenn Sie mit neuartigen Schließmechanismen experimentieren wollen, ist das am häufigsten verwendete Werkzeug, das ich in der akademischen Literatur verwendet habe, das Spin model checker. Es gibt auch ESP, die den Statusraum reduzieren könnte, aber ich weiß nicht, ob es auf gleichzeitige Probleme angewendet wurde, und auch die mobility workbench, die eine Analyse geben würde, wenn Sie Ihr Problem in Pi-Kalkül coachen können. Intel Parallel Inspector scheint nicht annähernd so kompliziert zu sein wie diese Tools, sondern mit Heuristiken nach häufig auftretenden Problemen zu suchen.

1

Ich bin ziemlich sicher, sollte es wie folgt umgesetzt werden:

class SpinLock 
{ 
    long lockValue; 
    SpinLock(long value) : lockValue(value) { } 

    void Lock() { 
     while(InterlockedCompareExchange(&lockValue, 1, 0) != 0) { 
      WaitABit(); 
     } 
    } 

    void Unlock() { InterlockedExchange(&lockValue, 0); } 
}; 
+0

Was Sie vorgeschlagen wird, ist ungefähr das Gleiche mit dem, was ich tun, nur, dass der int um Der Lock-Spins ist in der Klasse enthalten ... und das wäre ein Nachteil, weil RAII nicht mehr verwendet werden kann (die Klasse hat auch einen Destruktor, der die Sperre automatisch aufgibt). Dachte, ich habe versucht, was du gesagt hast, und es ist das gleiche: Das Programm funktioniert korrekt, aber Intel Parallel Inspector sagt, dass es eine Race Condition gibt. Vielleicht hat der Inspektor einen Fehler? Aber wahrscheinlich nicht :( –

+0

sollten Sie auch lange verwenden, um mit dem expliziten Cast zu beginnen, und im Konstruktor nehmen Sie keine Parameter und starten Sie es nur entsperrt. Wenn das Ding es erstellen muss es zu Beginn gesperrt haben, können sie nur Sperren Sie es nach dem Erstellen, aber bevor Sie es teilen. @Igratian - Sie brauchen RAII in diesem Fall nicht, da der Destruktor nichts zu bereinigen hat (es ist nur eine lange). –

+0

Edited.Ich werde mich nicht darum kümmern, den Dekonstruktor hinzuzufügen ... da die Frage nicht ausreicht, seinen Code vollständig zu korrigieren. Ich habe nur versucht, sein Problem zu lösen. – Goz

2

Für andere arme Leute in einer ähnlichen Situation zu mir: Intel bietet eine Reihe von Includes und Bibliotheken für genau diese Art von Sache. Überprüfen Sie im Inspector-Installationsverzeichnis (Sie sehen \ include, \ lib32 und \ lib64 im Installationsverzeichnis) für diese Materialien. Dokumentation, wie sie verwenden (Stand Dezember 2014):

https://software.intel.com/sites/products/documentation/doclib/iss/2013/inspector/lin/ug_docs/index.htm#GUID-E8B4A8F7-45C3-489C-A5E3-1C9CC525BA9C.htm

Es gibt 3 Funktionen:

void __itt_sync_acquired(void *addr) 
void __itt_sync_releasing(void *addr) 
void __itt_sync_destroy(void *addr) 
+0

Ich habe das mit meinem eigenen Spin-Lock-Mutex getestet und es funktioniert wie erwartet (Datenrennen verschwindet aus dem Parallel Inspector-Bericht) – Julio

+0

Gern geschehen. – johnwbyrd