Es ist nicht ganz so einfach, wie es scheinen mag, mit Ausnahme von zwei Fällen:
- Wenn es nur Leser und keine Autoren, Sie nicht benötigen, immer zu synchronisieren.
- Wenn mehrere Threads schreiben und mindestens einer von ihnen eine Lese-Modify-Write-Operation ausführt (wie
++x;
), müssen Sie immer synchronisieren, oder Sie erhalten völlig unvorhersehbare Ergebnisse.
In allen anderen Fällen, wenn Sie mindestens ein Schriftsteller und einen Leser (oder mehrere Autoren) haben, können Sie in der Regel (mit wenigen Ausnahmen) benötigen Zugang zu synchronisieren, aber nicht unbedingt immer, und nicht immer auf die strengste Art und Weise.
Es hängt sehr viel davon ab, was Sie brauchen. Einige Anwendungen benötigen strikte sequenzielle Konsistenz über Threads (und manchmal müssen Sie sogar Lock Fairness). Einige Anwendungen werden gleich gut funktionieren, aber mit einer viel besseren Leistung, wenn sie nur innerhalb des gleichen Threads "happen-before" -Garantien haben. Andere Anwendungen brauchen nicht einmal so viel und sind völlig zufrieden mit entspannten Operationen oder ohne irgendwelche Garantien.
Zum Beispiel dieser „typische“ Implementierung eines Worker-Thread hat einen Autor und einen Leser:
// worker thread
running = true;
while(running) { task = pull_task(); execute(task); }
// main thread exit code
running = false;
join(workerthread);
Dies ohne Synchronisation sehr gut funktioniert. Ja, pedantisch ist es undefiniert, wann oder wie sich der Wert von running
ändert, aber in Wirklichkeit macht das keinen Unterschied. Es gibt keine Möglichkeit, dass der Speicherort einen "zufälligen" Zwischenwert hat, und es spielt keine Rolle, ob die Änderung einige Dutzend Sekunden früher oder später sichtbar wird, da der Worker-Thread höchstwahrscheinlich ohnehin damit beschäftigt ist, eine Aufgabe auszuführen im schlimmsten Fall nimmt es einige Millisekunden später die Änderung auf. Bei der nächsten Iteration wird der Worker-Thread die Änderung übernehmen und wird beendet.
Die SPS-Fast-Forward-Queue, die vor einigen Jahren in Dr. Dobb veröffentlicht wurde, arbeitete nach einem ähnlichen Prinzip, nur mit Zeigern.
Eine gute und umfassende Lektüre über die vielen verschiedenen Synchronisationsmodi und ihre Auswirkungen finden Sie in der GCC documentation.
Fälle 2 und 3, d. H. Jede Situation, in der mindestens ein Thread mit mindestens einem anderen Thread liest oder schreibt. – juanchopanza
Sie müssen nicht immer sperren, wenn Sie auf Daten von verschiedenen Threads zugreifen. Schauen Sie sich atomare Operationen an, und besonders bei C++ 11's 'std :: atomic' – nijansen
Und ja, um Ihren letzten Satz zu adressieren, kann es bei Multicore-CPUs mehrere Kopien jedes Wertes in den verschiedenen Cache-Ebenen geben. – Hulk