2017-02-11 2 views
1

Ich habe einen Code in Arbeit, der mehrere Threads startet, die einige Operationen ausführen, und wenn einer von ihnen fehlschlägt, setzen sie die freigegebene Variable auf false.Gibt es eine implizite Speicherbarriere mit synchronisierten Beziehungen auf Thread :: Join?

Dann verbindet Hauptthread alle Worker-Threads. Simulation sieht das ungefähr so ​​(ich aus der möglichen Lösung kommentiert, die ich weiß nicht, ob es gebraucht wird):

#include <thread> 
#include <atomic> 
#include <vector> 
#include <iostream> 
#include <cassert> 

using namespace std; 

//atomic_bool success = true; 
bool success = true; 

int main() 
{ 
    vector<thread> v; 
    for (int i = 0; i < 10; ++i) 
    { 
     v.emplace_back([=] 
     { 
      if (i == 5 || i == 6) 
      { 
       //success.store(false, memory_order_release); 
       success = false; 
      } 
     }); 
    } 
    for (auto& t : v) 
     t.join(); 

    //assert(success.load(memory_order_acquire) == false); 
    assert(success == false); 

    cout << "Finished" << endl; 
    cin.get(); 
    return 0; 
} 

Gibt es eine Möglichkeit, dass Hauptthread obwohl die Erfolgsvariable als wahr sogar lesen einer der Arbeiter setzte es auf false?

Ich fand, dass Thread :: join() ist eine vollständige Speichersperre (source), aber das mit dem von Erfolg Variable aus dem Haupt-Thread lesen folgenden synchronisierten mit Beziehung bedeutet, so dass wir hast du garantiert den neuesten Wert?

Ist die Korrektur, die ich (in dem kommentierten Code) gepostet habe, notwendig in diesem Fall (oder vielleicht eine andere Korrektur, wenn diese falsch ist)?

Gibt es eine Möglichkeit, dass der Erfolg Variable gelesen wird entfernt werden optimiert (da es nicht flüchtig ist), und wir werden alte Wert erhalten, unabhängig von suppossed implizite Gedächtnis Barriere auf Thread existieren :: beitreten?

Der Code ist für die Arbeit mit mehreren Architekturen (ich kann mich nicht an alle erinnern, ich habe kein Makefile vor mir), aber es gibt atleast x86, amd64, itanium, arm7.

Danke für jede Hilfe mit diesem.

Edit: Ich habe das Beispiel geändert, weil in der realen Situation mehr als ein Thread versuchen kann, Erfolg Variable schreiben.

+1

Ist die Quelle nicht klar darüber? "Da die Erstellung und Struktur von Threads als eine Synchronisierungsoperation definiert ist, wird ein Thread nach dem Ende dieses Threads notwendigerweise verbunden. So sehen Sie alles, was unbedingt geschehen muss, bevor der Thread beendet wurde." –

+0

Ich bin mir nicht sicher seit, wie Sie hier http: //en.cppreference sehen können.com/w/cpp/atomic/atomic_thread_fence Verweis erwähnt nur die Synchronisation zwischen Zäunen und atomaren Objekten, gibt es nichts über die Synchronisation zwischen Zäunen und gewöhnlichen Objekten. Ich denke, beitreten verwendet solche Zaun intern, aber ich kann falsch liegen. – Mikaka

+1

[Ja] (https://timsong-cpp.github.io/cppwp/thread.thread.member#4). Sonst wäre "Join" eher nutzlos. –

Antwort

1

Der obige Code stellt ein Datenrennen dar, und die Verwendung von join kann diese Tatsache nicht ändern. Wenn nur ein Thread an die Variable schrieb, wäre das in Ordnung. Aber Sie haben zwei Threads schreiben, mit keine Synchronisation zwischen ihnen. Das ist ein Datenrennen.

join bedeutet einfach "alle Nebeneffekte der Operation dieses Threads sind abgeschlossen und sind nun für Sie sichtbar." Das erstellt keine Reihenfolge oder Synchronisierung zwischen diesem Thread und einem Thread anderen als Ihr eigenes.

Wenn Sie eine atomic_bool verwendet haben, dann wäre es nicht UB; es wäre garantiert falsch. Da es jedoch ein Datenrennen gibt, erhalten Sie reines UB. Es könnten wahre, falsche oder nasale Dämonen sein.

+0

Ok ich bekomme den undefinierten Verhaltensteil. Aber vorausgesetzt, wir befinden uns auf der Plattform, wo schreiben zu bool atomar ist, und mein Thread (der alle Arbeiter verbindet) ist der einzige, der die * success * -Flagge liest, wird * join * genug sein, um korrekte Reihenfolge zu garantieren und ich werde sehe immer * falsch * wenn ein Arbeiter es setzt oder kann ich trotzdem * wahr * bekommen? – Mikaka

+0

@Mikaka: "* Aber vorausgesetzt, wir sind auf der Plattform, wo schreiben zu bool Atom ist *" Nein. Sie fragte nach C++. Ich sage dir, was C++ garantiert. Wie "arbiträre Plattform, von der ich hoffe, dass sie etwas Vernünftiges tut", ist eine Angelegenheit zwischen Ihnen und Ihrer bevorzugten Plattform. Wenn Sie möchten, dass dies * garantiert * funktioniert, verwenden Sie eine tatsächliche 'atomare '. Wenn das eine Plattform ist, die sich so verhält, wie Sie denken, dann ist "atomic " nur ein dünner Wrapper um einen 'Bool'. Und wenn nicht, dann wird es immer noch korrekt sein. –

Verwandte Themen