2009-09-24 15 views
9

Zrobiłem bardzo prosty spinlock za pomocą funkcji powiązanych w Windows i przetestowałem go na dwurdzeniowym procesorze (dwa wątki, które zwiększają zmienną);Intel Inspektor raportuje wyścig danych w mojej implementacji spinlock

Program wydaje się działać OK (daje ten sam wynik za każdym razem, co nie jest w przypadku, gdy nie jest używany do synchronizacji), ale Intel Parallel Inspector mówi, że istnieje sytuacja wyścigu w wartości + = j (patrz poniższy kod). Ostrzeżenie znika podczas używania Sekcji krytycznych zamiast mojego SpinLocka.

Czy moja implementacja SpinLock jest poprawna czy nie? To naprawdę dziwne, ponieważ wszystkie używane operacje są atomowe i mają odpowiednie bariery pamięciowe i nie powinny prowadzić do warunków wyścigowych.

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); } 
}; 

Program testowy:

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; 
} 

Odpowiedz

4
dokumentacja

Parallel inspektora do data race sugeruje użycie sekcji krytycznej lub mutex naprawić wyścigi w systemie Windows. Nic w nim nie sugeruje, że Inspektor Równoległy wie, jak rozpoznać każdy inny mechanizm blokujący, który możesz wymyślić.

Narzędzia do analizy nowatorskich mechanizmów blokujących są zwykle statycznymi narzędziami, które analizują każdą możliwą ścieżkę za pośrednictwem kodu, dokumentacja Parallel Inspector sugeruje, że wykonuje kod raz.

Jeśli chcesz poeksperymentować z nowatorskimi mechanizmami blokującymi, najczęściej używanym narzędziem używanym w literaturze akademickiej jest Spin model checker. Istnieje również ESP, która może zmniejszyć przestrzeń stanu, ale nie wiem, czy została ona zastosowana do współbieżnych problemów, a także mobility workbench, która dałaby analizę, jeśli możesz umieścić swój problem w pi-rachunku. Intel Parallel Inspector nie wydaje się być tak skomplikowany jak te narzędzia, ale raczej zaprojektowany do sprawdzania często występujących problemów przy użyciu heurystyki.

1

jestem całkiem pewny, powinno być realizowane w następujący sposób:

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

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

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

Co proponowana jest o tym samym co ja, tylko że int wokół spiny blokady są zawarte w klasie ... i byłoby to wadą, ponieważ nie można już używać RAII (klasa ma również destruktor, który automatycznie zwalnia blokadę). Pomyślałem, próbowałem tego, co powiedziałeś, i to jest to samo: program działa poprawnie, ale Intel Parallel Inspector mówi, że istnieje stan wyścigu. Może inspektor ma błąd? Ale prawdopodobnie nie :(od –

+0

powinieneś także użyć długiego na początku, zamiast wykonywać wyraźną obsadę, aw konstruktorze nie pobierać żadnych parametrów i po prostu uruchamiać go odblokowany .Jeżeli stworzenie to musi mieć zablokowane na początek, mogą po prostu zablokuj go po utworzeniu, ale przed udostępnieniem go. @Illian - W tym przypadku nie potrzebujesz RAII, ponieważ destruktor nie ma nic do wyczyszczenia (jest tylko długi) –

+0

Edytowany.Nie zawracaj sobie głowy dodawaniem dekonstruktora ... ponieważ to pytanie nie gwarantuje całkowitej korekty jego kodu. Próbowałem tylko rozwiązać jego problem. – Goz

2

Dla innych biednych ludzi w podobnej sytuacji jak ja: Intel DOES dostarcza zestaw załączników i bibliotek do robienia dokładnie tego rodzaju rzeczy. Sprawdź w katalogu instalacyjnym Inspektora (zobaczysz \ include, \ lib32 i \ lib64 w katalogu instalacyjnym) dla tych materiałów. Dokumentacja na temat sposobu korzystania z nich (od grudnia 2014):

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

Istnieją 3 funkcje:

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

Przetestowałem to z moim własnym muteksem spin-lock i działa zgodnie z oczekiwaniami (dane-wyścig znikną z raportu Parallel Inspector) – Julio

+0

Nie ma za co. – johnwbyrd

Powiązane problemy