2017-04-19 1 views
2

Ich denke, mein Programm hat einen Fehler, weil manchmal, wenn ich mein Programm ausführen, gibt es eine niedrigere Zahl als 30000, wie 29999. Aber manchmal läuft es richtig und erreicht die 30000. Meine Frage ist, wie kann ich das beheben und warum ist es passiert.Warum endet mein Thread-Zähler nicht immer?

#include <iostream> 
#include <thread> 

using namespace std; 

int counter; 
int i; 

void increment() 
{ 
counter++; 
} 

int main() 
{ 
counter = 0; 

cout << "The value in counter is : " << counter << endl; 
thread tarr[30000]; 

    for (i = 0; i < 30000; i++) 
    { 
     tarr[i] = thread(increment); 
    } 

    for (i = 0; i < 30000; i++) 
    { 
     tarr[i].join(); //main thread waits for tarr to finish 
    } 

cout << "After running 30,000 threads "; 
cout << "the value in counter is : " << counter << endl; 
return 0; 
} 
+0

Der Schritt ist vollständig * * unbewacht und ein Rezept für eine Race-Bedingung. Und Sie sollten dankbar sein, dass fast alle Ihre Threads so schnell fertig sind wie sie, denn 30000 Threads sind ungefähr 27000 mehr als die meisten Desktop-Betriebssysteme, ohne dass sie sich selbst übergeben und sich zu einem alptraumhaften Stillstand bewegen müssen. – WhozCraig

+0

@aghilpro die Threads sind alle bereits vor den letzten zwei 'Cout' Dumps verbunden. Was denkst du, denkst du, dass ein "Schlaf" ausreichen wird? – WhozCraig

+0

Nach einem guten Schlaf ist es oft besser. Du erwachst erfrischt und bereit für einen weiteren Blick auf den Code und ... Oh Schlaf. Ja, das wäre nicht sehr hilfreich. – user4581301

Antwort

2

Das Problem ist, dass counter++can be broken down into three operations:

  1. Lastanfangswert
  2. Increment den Wert
  3. Speichern der neuen Wert zurück Speicher registrieren

ein einzelner Thread kann die ersten beiden Schritte machen und dann die Kontrolle an einen anderen Thread weitergeben, um das sa zu machen mich. Was kann das bedeuten, ist:

  1. Thema liest man counter als 5
  2. Thema einer seiner internen Kopie 6
  3. Thema zwei liest counter als 5
  4. Thema zwei bis 6 Schritten seine interne Kopie erhöht
  5. Thread zwei schreibt zurück 6 zu counter
  6. ein
  7. Thema schreibt zurück 6 zu counter

Sie sollten counterstd::atomic machen, oder schützen sie mit einem std::mutex:

std::atomic<int> counter; 
+0

Während der "in drei Operationen gebrochene" Teil vernünftig klingt, laut C++ ist eigentlich Undefined Behavior. Dies ist wichtig, weil das hier vorgestellte Modell darauf hindeutet, dass die Bandbreite der möglichen Ergebnisse geringer ist als in der Realität. Insbesondere schlägt diese Antwort vor, dass der Zähler um mindestens einen Thread inkrementiert werden muss, so dass das Ergebnis zwischen 1 und 30.000 liegen muss. Ein vernünftiger optimierender Compiler kann alle unsicheren Zuweisungen zu "counter" entfernen, was ein ebenso gültiges Ergebnis von 0 ergibt. Dennoch ist die endgültige Schlussfolgerung dieser Antwort richtig. – MSalters