Im Papier mit dem gleichen Titel wie die von dieser Frage, beschreiben die Autoren , wie ein bauen , nicht blockierend linearisierbar Mehrwort CAS nur mit einem einzigen Wort CAS Betrieb. Sie führen zunächst die Double-Compare-Single-Swap-Operation - RDCSS - wie folgt ein:
word_t RDCSS(RDCSSDescriptor_t *d) {
do {
r = CAS1(d->a2, d->o2, d);
if (IsDescriptor(r)) Complete(r);
} while (IsDescriptor(r));
if (r == d->o2) Complete(d); // !!
return r;
}
void Complete(RDCSSDescriptor_t *d) {
v = *(d->a1);
if (v == d->o1) CAS1(d->a2, d, d->n2);
else CAS1(d->a2, d, d->o2);
}
Dabei RDCSSDescriptor_t
ist das eine Struktur mit folgenden Feldern:
a1
- Adresse der ersten Bedingungo1
- Wert erwartet an der ersten Adressea2
- Adresse der zweiten Bedingungo2
- Wert erwartet an der zweiten Adressen2
- der neue Wert, der an die zweite Adresse geschrieben werden soll
Dieser Deskriptor wird einmal in einem Thread erstellt und initialisiert, der die RDCSS-Operation initiiert. Kein anderer Thread hat einen Verweis darauf, bis das erste CAS1 in der Funktion RDCSS
erfolgreich ist, wodurch der Deskriptor erreichbar (oder in der Terminologie des Dokuments aktiv ) wird.
Die Idee hinter dem Algorithmus ist die folgende: Ersetzen Sie den zweiten Speicherort durch einen Deskriptor, der angibt, was Sie tun möchten. Wenn der Deskriptor vorhanden ist, überprüfen Sie den ersten Speicherort, um festzustellen, ob sich sein Wert geändert hat. Ist dies nicht der Fall, ersetzen Sie den Deskriptor am zweiten Speicherort durch den neuen Wert. Andernfalls setzen Sie den zweiten Speicherort auf den alten Wert zurück.
Die Autoren erklären nicht, warum die Zeile mit dem !!
Kommentar innerhalb des Papiers notwendig ist. Es scheint mir, dass die CAS1
Anweisungen in der Complete
Funktion nach dieser Überprüfung immer fehlschlagen, vorausgesetzt, es erfolgt keine gleichzeitige Änderung. Und wenn es eine gleichzeitige Änderung zwischen der Prüfung und dem CAS-Eingang gab Complete
, sollte der Thread, der die Prüfung durchführt, immer noch mit seinem CAS-Eingang fehlschlagen Complete
, da die gleichzeitige Änderung nicht denselben Deskriptor verwenden sollte d
.
Meine Frage ist: Kann die Prüfung in der Funktion RDCSSS
, if (r == d->o2)...
weggelassen wird, mit RDCSS noch die Semantik einer Doppel vergleichen, einzelnen Swap - Anweisung beibehalten , die ist linearisierbar und Lock-frei ? (Zeile mit !!
Kommentar)
Wenn nicht, können Sie das Szenario beschreiben, in dem diese Zeile tatsächlich erforderlich ist, um die Richtigkeit sicherzustellen?
Vielen Dank.
quelle
Antworten:
In einer gleichzeitigen Laufzeitumgebung können einfache Dinge seltsam erscheinen ... hoffe, dies kann helfen.
Wir haben ein eingebautes ATOM-CAS1 mit dieser Semantik:
Wir müssen eine ATOMIC RDCSS-Funktion mit CAS1 definieren und die folgende Semantik haben:
Intuitiv: Wir müssen den Wert bei addr2 nur dann regelmäßig ändern, wenn * addr1 == oldval1 ... wenn ein anderer Thread ihn ändert, können wir dem anderen Thread helfen, den Vorgang abzuschließen, dann können wir es erneut versuchen.
Die RDCSS- Funktion wird verwendet (siehe Artikel), um CASN zu definieren. Nun definieren wir einen RDCSS-Deskriptor folgendermaßen:
Dann implementieren wir RDCSS folgendermaßen:
ANTWORT AUF IHRE FRAGE
Wenn wir STEP4 weglassen, wird der Teil if (... && * addr1 == oldval1) * addr2 = newval2 der RDCSS-Semantik niemals ausgeführt (... oder besser: Er kann auf unvorhersehbare Weise von anderen helfenden Threads ausgeführt werden der aktuelle).
Wie Sie in Ihrem Kommentar ausgeführt haben, ist die Bedingung if (res == d1-> oldval2) bei STEP4 nicht erforderlich: Selbst wenn wir sie weglassen, schlagen beide CAS1 in Complete () fehl, weil * (d-> addr2)! = D. . Ihr einziger Zweck ist es, einen Funktionsaufruf zu vermeiden.
Beispiel T1 = Thread1, T2 = Thread2:
quelle
addr2
enthältd2->newval2
. Aber es scheint mir, dass das CAS1 imComplete
Testament einfach fehlschlägt, weil es erwartet, dass der alte Wert der Deskriptor istd1
- nichts wird von T1 geschrieben. Recht?