Code: Select all
#include
#include
#include
std::atomic canceller = {0};
int main() {
auto t1 = std::thread([]() {
auto v = canceller.fetch_add(1, std::memory_order::relaxed); // #0
std::thread([v]() {
int current = v + 1;
if (canceller.compare_exchange_strong(
current, current, std::memory_order::relaxed,
std::memory_order::relaxed)) { // #1
// post_data_to_network(current);
}
}).join();
});
auto t2 = std::thread([]() {
canceller.fetch_add(1, std::memory_order::relaxed); // #2
});
t1.join();
t2.join();
}
Der obige Code modelliert solche zwei Ereignisse. In diesem Fall muss #1 fehlschlagen (die Änderung erkennen) und die Aufgabe abbrechen, wenn #2 #0 liest und 2 schreibt. Wenn jedoch #1 in ein reines Laden geändert wird, wie folgt:
Code: Select all
if(canceller.load(memory_order::relaxed)==current){
// post_data_to_network(v);
}
Wenn ein Nebeneffekt />
Die Implementierung sollte Atomspeicher für Atomladungen sichtbar machen, und Atomladungen sollten Atomspeicher innerhalb einer angemessenen Zeitspanne beobachten.
Theoretisch kann die reine Last in A für eine begrenzte Zeit weiterhin 1 lesen, wodurch die Änderung von #0 in B nicht erkannt werden kann, obwohl #2 den Wert geändert hat.
Unter derselben Untersequenzänderung in der Änderungsreihenfolge des Stornierers:
Code: Select all
0 < #0 < #2 < ...
Ich frage mich also, ob ein CAS, der denselben Wert schreibt, eine höhere Wahrscheinlichkeit hat, die Änderung zu erkennen als eine reine Last? Wenn nicht, wie beweisen Sie dann, dass ihre Erfolgsquoten gleich sind?
Aktualisierung
Wie @PeterCordes in seinen Kommentaren betonte, lässt sich die Wahrscheinlichkeit einer erfolgreichen Stornierung nicht mit dem Tag [Language-Lawyer] beantworten; Stattdessen handelt es sich um eine [CPU-Architektur]-Antwort. Allerdings erklärte er in seinem Kommentar nicht, warum. Welche Bedingungen sollten wir konkret haben, um die Wahrscheinlichkeit zu beweisen, aber die abstrakte Maschine verfügt nicht über diese Bedingungen? Dies könnten die Antworten auf diese Frage sein.
Mobile version