Wird flüchtiges Bool für die Thread-Kontrolle als falsch angesehen?
Als Ergebnis meiner Antwort auf diese Frageich begann zu Lesen über das Schlüsselwort volatile
und was den Konsens betrifft. Ich sehe, es gibt eine Menge von Informationen über Sie, einige alt, das scheint jetzt falsch und viel neues, das sagt, es hat fast keinen Platz in der multi-threaded Programmierung. Daher möchte ich zur Klärung einer bestimmten Nutzung (konnte Sie nicht finden, eine genaue Antwort hier SO).
Ich möchte auch darauf hinweisen, verstehe ich die Anforderungen für das schreiben von multi-threaded code im Allgemeinen und warum volatile
ist nicht die Lösung der Dinge. Trotzdem sehe ich code mit volatile
für thread-Steuerelement im code-Basen in dem ich arbeite. Weiter, dies ist der einzige Fall, ich benutze die volatile
Schlüsselwort als alle anderen freigegebenen Ressourcen werden richtig synchronisiert.
Sagen, dass wir eine Klasse haben wie:
class SomeWorker
{
public:
SomeWorker() : isRunning_(false) {}
void start() { isRunning_ = true; /* spawns thread and calls run */ }
void stop() { isRunning_ = false; }
private:
void run()
{
while (isRunning_)
{
//do something
}
}
volatile bool isRunning_;
};
Für Einfachheit sind einige Dinge ausgelassen, aber das wichtigste ist, dass ein Objekt erstellt wird, das etwas tut, in eine neu erzeugte thread-Prüfung ein (volatile
) boolean wissen wenn man aufhören sollte. Dieser Boolesche Wert gesetzt ist, aus einem anderen thread, Wann immer es will, dass die Arbeiter zu stoppen.
Mein Verständnis war, dass der Grund für die Verwendung volatile
in diesem speziellen Fall ist einfach zu vermeiden-Optimierung, cache würde es in ein register für die Schleife. Also, was in einer unendlichen Schleife. Es gibt keine Notwendigkeit, um richtig zu synchronisieren die Dinge, weil der worker-thread wird irgendwann der neue Wert?
Ich würde gerne verstehen, ob dies als völlig falsch und wenn der richtige Ansatz ist die Verwendung eines synchronisierten Variablen? Gibt es einen Unterschied zwischen compiler/Architektur/Kerne? Vielleicht ist es nur eine schlampige Ansatz lohnt sich vermeiden?
Ich würde mich freuen, wenn jemand würde dies klären. Danke!
BEARBEITEN
Ich wäre daran interessiert zu sehen (im-code), wie Sie sich entscheiden, diese zu lösen.
InformationsquelleAutor der Frage murrekatt | 2011-08-09
Du musst angemeldet sein, um einen Kommentar abzugeben.
volatile
kann werden für solche Zwecke eingesetzt. Jedoch dies ist eine Erweiterung zu standard-C++ -von Microsoft:Ist, soweit ich das verstanden habe, wenn Sie die Visual C++ - compiler, ein
volatile bool
ist für die meisten praktischen Zwecke eineatomic<bool>
.Es sollte angemerkt werden, dass neuere VS-Versionen fügen Sie ein /volatile-Schalter , steuert dieses Verhalten, so dass diese nur gilt, wenn
/volatile:ms
aktiv ist.InformationsquelleAutor der Antwort Martin Ba
Brauchen Sie nicht eine synchronisiert variable, sondern eine atomic variable. Zum Glück, können Sie einfach
std::atomic<bool>
.Die entscheidende Frage ist, dass, wenn mehr als ein thread greift auf den gleichen Speicher gleichzeitig, dann es sei denn, der Zugang ist atomicdas gesamte Programm aufhört zu sein, in einem gut definierten Zustand. Vielleicht hast du Glück mit einem bool, die möglicherweise immer aktualisiert atomar in jedem Fall, aber der einzige Weg zu sein, offensiv sicher du machst es richtig, ist die Verwendung von atomaren Variablen.
"Zu sehen, die codebase, in der Sie arbeiten" ist wohl nicht eine sehr gute Maßnahme, wenn es darum geht zu lernen, concurrent programming. Gleichzeitige Programmierung ist teuflisch schwierig und nur sehr wenige Menschen verstehen es voll und ich bin bereit zu Wetten, dass die überwiegende Mehrheit der homebrew-code (also nicht über eine dedizierte gleichzeitige Bibliotheken im ganzen) ist fehlerhaft in gewisser Weise. Das problem ist, dass solche Fehler kann sehr schwer zu beobachten oder zu vervielfältigen, so dass Sie möglicherweise nie wissen.
Edit: Sie sagen nicht, dass Sie Ihre Frage wie bool-wird immer aktualisiert, also nehme ich an das Schlimmste. Wenn Sie wickeln Ihre gesamte update-operation in eine Globale Sperre für eine Instanz, dann gibt es natürlich keine gleichzeitige Speicherzugriff.
InformationsquelleAutor der Antwort Kerrek SB
Gibt es drei große problem, das Sie konfrontiert sind, wenn multithreading:
1) Synchronisierung und thread-Sicherheit. Variablen werden gemeinsam von mehreren threads müssen davor geschützt werden, auf die geschrieben wird von mehreren threads auf einmal, und verhindert, dass Lesen während der nicht-atomaren schreibt. Synchronisation von Objekten kann nur durch eine spezielle semaphore/mutex-Objekt, das garantiert atomic von selbst. Das volatile-Schlüsselwort nicht helfen.
2) Instruktion Rohrleitungen. Eine CPU, die Reihenfolge zu ändern, in dem einige Anweisungen, die ausgeführt werden, um code schneller laufen. In einem multi-CPU-Umgebung, wo ein thread ausgeführt wird pro CPU, die CPUs Rohr Anweisungen, ohne zu wissen, dass eine andere CPU im system ist das gleiche zu tun. Schutz gegen Unterricht Rohrleitungen heißt memory-Barrieren. Es ist alles gut erklärt auf Wikipedia. Speicher Barrieren implementiert werden kann, entweder durch dedizierte memory-Barriere-Objekten oder durch das semaphor/mutex-Objekt im system. Ein compiler könnte möglicherweise wählte zum aufrufen einer memory-Barriere in den code, wenn das volatile-Schlüsselwort verwendet wird, aber das wäre eher die Besondere Ausnahme und nicht die Regel. Ich würde nie davon ausgehen, dass das volatile-Schlüsselwort geschafft haben, ohne es verifiziert, die in der compiler-Handbuch.
3) Compiler Unwissenheit von callback-Funktionen. Genauso wie für hardware-interrupts, einige Compiler kann nicht wissen, dass eine callback-Funktion ausgeführt wurde und aktualisiert den Wert in der Mitte des Codes. Können Sie code wie diesen:
Beachten Sie, dass dieses problem erscheint nur auf einige Compiler, je nach optimizer-Einstellungen. Dieses problem wird gelöst durch das volatile-Schlüsselwort.
Also die Antwort auf die Frage ist: in einem multi-threaded Programm, das volatile-Schlüsselwort nicht helfen, mit thread-Synchronisation/Sicherheit, tut es wahrscheinlich nicht als memory-Barriere, aber es könnte verhindern, dass gegen gefährliche Annahmen durch den compiler optimizer.
InformationsquelleAutor der Antwort Lundin
Mit
volatile
ist genug, nur auf single-cores, wo alle threads die gleiche cache. Auf multi-cores, wennstop()
genannt wird, auf einem Kern undrun()
ausgeführt wird, auf einem anderen, es könnte einige Zeit dauern, für die CPU-caches zu synchronisieren, was bedeutet, dass zwei Kerne vielleicht sehen zwei unterschiedliche AnsichtenisRunning_
. Dies bedeutetrun()
wird für eine Weile laufen, nachdem er angehalten wurde.Wenn Sie die Synchronisierung verwenden Mechanismen, die Sie sicherstellen, dass alle caches Holen Sie sich die gleichen Werte, die im Preis stagnieren, das Programm für eine Weile. Ob Leistung oder Korrektheit wichtiger, hängt von Ihrem tatsächlichen Bedarf.
InformationsquelleAutor der Antwort eran
Dieser Arbeit wird für Ihren Fall aber zum Schutz eines kritischen Abschnitts dieser Ansatz ist falsch. Wenn es richtig ist, dann könnte man verwenden, eine volatile bool in fast allen Fällen, in denen ein mutex verwendet wird. Der Grund dafür ist, dass eine volatile-variable nicht garantieren Durchsetzung Speicher Barrieren noch alle cache-Kohärenz-Mechanismus. Im Gegenteil, ein mutex hat. In anderen Worten, sobald ein mutex gesperrt ist eine cache-Invalidierung broadcast an alle Kerne, um die Konsistenz zu wahren unter aller Kerne während. Mit volatile dies ist nicht der Fall.
Dennoch, Andrei Alexandrescu vorgeschlagen einen sehr interessanten Ansatz zu verwenden volatile zu erzwingen Synchronisation auf ein gemeinsames Objekt. Und wie Sie sehen werden, er tut es mit einem mutex; volatile wird nur verwendet, um zu verhindern, dass der Zugriff auf das Objekt die Schnittstelle, ohne die Synchronisierung.
InformationsquelleAutor der Antwort PoP