2016-11-22 2 views
-1

Ich habe einen Fehler in meinem Code, den ich als Race Condition identifiziert habe. Ich weiß, dass es eine Race Condition ist, weil es intermittierend auftritt. Ich habe recherchiert, wie man diese Rennbedingungen zu verhindern, und ich kam in dieserSo verwenden Sie Sperren, um eine Wettlaufsituation zu verhindern

 for (int i = 0; i < 10000000; i++) 
     { 
      //lock x 
      x = x + 1; 
      //unlock x 
     } 

Könnte jemand gehen Sie bitte weiter ins Detail auf, wie ich diese Sperren implementiert kann?

+4

Wenn Sie 'pthread's verwenden, dann können Sie' pthread_mutex_lock' verwenden und 'pthread_mutex_unlock' –

+1

Der einfachste Weg, wenn Sie C++ 11 haben, ist 'std :: atomic x;'. –

Antwort

2

Ich weiß, dass es eine Race-Bedingung ist, weil es zeitweise

tritt Während Rennbedingungen typischerweise intermittierend auftreten, gibt es andere Arten von Fehlern, die ein ähnliches Verhalten haben, so dass Ihre Argumentation ist nicht garantiert um genau zu sein. Das heißt, ohne das Programm zu sehen, ist dies ein sehr wahrscheinliches Problem in einem Programm mit mehreren Threads.

Könnte jemand bitte ausführlicher darüber sprechen, wie ich diese Sperren implementieren kann?

Eine gegenseitige Ausschlusssperre kann in C++ nicht implementiert werden. Sie werden typischerweise unter Verwendung eines Maschinenbefehls Test-and-set implementiert.

Sie müssen jedoch selbst keine Sperre implementieren. Seit C++ 11 enthält die Standardbibliothek bereits eine Implementierung. Noch besser, es enthält atomare Typen auf höherer Ebene (std::atomic), die einen atomaren Zugriff ermöglichen, ohne die Ausführung explizit zu sperren (die Implementierung atomarer Typen kann sogar effizientere Anweisungen verwenden, die abhängig von der Zielarchitektur ein Sperren vermeiden).

Wenn Ihre Standardbibliothek veraltet ist, können Sie die von Ihrem Betriebssystem bereitgestellte Threading-API verwenden. Es bietet fast auf jeden Fall eine Art von Mutex Struktur.

4

Ihr Beispiel schlägt vor, dass alles, was Sie in Ihren Threads tun möchten, eine Operation auf einer int-Variablen ist. Wenn das wirklich der Fall ist, wie andere darauf hingewiesen haben, ist std::atomic wahrscheinlich der einfachste Weg, es zu implementieren.

#include <thread> 
#include <atomic> 
#include <iostream> 

std::atomic<int> x = 0; 

void increment() 
{ 
    for(int i = 0; i < 10000000; ++i) 
    { 
     ++x; 
    } 
} 

int main() 
{ 
    std::thread t1(increment); 
    std::thread t2(increment); 

    t1.join(); 
    t2.join(); 

    std::cout << x; 
} 

jedoch gleichzeitig in mehreren Threads zu schützen ausgeführt kompliziertere Operationen aus wird, sollten Sie std::lock_guard verwenden. Es verwendet das RAII-Prinzip (Resource Acquisition is Initialization), um einen Mutex für seine Lebenszeit zu sperren.

#include <thread> 
#include <mutex> 
#include <iostream> 

int x = 0; 
std::mutex mtx; 

void increment() 
{ 
    for (int i = 0; i < 10000000; i++) 
    { 
     std::lock_guard<std::mutex> lock(mtx); //lock mtx 
     ++x; 

     // mtx is automatically released when lock 
     // goes out of scope -> RAII 
    } 
} 

int main() 
{ 
    std::thread t1(increment); 
    std::thread t2(increment); 

    t1.join(); 
    t2.join(); 

    std::cout << x; 
} 

EDIT

Basierend auf Ihre Kommentare hier ein anderes Beispiel ist:

#include <thread> 
#include <mutex> 
#include <iostream> 

class Foo 
{ 
public: 
    void increment() 
    { 
     for (int i = 0; i < 10000000; ++i) 
     { 
      std::lock_guard<std::mutex> lock(mtx); //lock mtx 
      ++x; 

      // mtx is automatically released when lock 
      // goes out of scope -> RAII 
     } 
    } 

    void decrement() 
    { 
     for (int i = 0; i < 10000000; ++i) 
     { 
      std::lock_guard<std::mutex> lock(mtx); //lock mtx 
      --x; 

      // mtx is automatically released when lock 
      // goes out of scope -> RAII 
     } 
    } 

    static int x; 
    static std::mutex mtx; 
}; 

int Foo::x = 0; 
std::mutex Foo::mtx; 

int main() 
{ 
    std::thread t1(&Foo::increment, Foo()); 
    std::thread t2(&Foo::decrement, Foo()); 

    t1.join(); 
    t2.join(); 

    std::cout << Foo::x; 
} 
+0

Wenn die Variable innerhalb einer Objektelementfunktion ist, kann ich diesen Code trotzdem implementieren? – MagnusHimmler

+0

Nicht sicher, ob ich dich richtig verstehe. Vielleicht können Sie Ihre Frage mit einem kleinen Beispiel bearbeiten? Wenn Ihre Variable jedoch eine lokale Variable in einer Member-Funktion ist, bezweifle ich kaum, dass Ihr Problem eine Race-Bedingung in Bezug auf diese Variable ist. – sigy

+0

Ich habe eine statische Variable, auf die zwei verschiedene Funktionen innerhalb desselben Objekts zugreifen. Manchmal überspringt die zweite Funktion diese Variable jedoch ganz. – MagnusHimmler

Verwandte Themen