__sync_val_compare_and_swap vs __sync_bool_compare_and_swap
Habe ich mir Gedanken über die return-Werte dieser beiden Funktionen. Die __sync_bool_compare_and_swap-Funktion den Rückgabewert zu haben scheint offensichtliche Vorteile, also kann ich es verwenden, um zu sagen, ob die swap-operation stattfand. Allerdings kann ich nicht sehen, einen guten Gebrauch von __sync_val_compare_and_swap Rückgabewert.
Erstens, können eine Funktion Signatur-Referenz (von GCC-docs minus die var args):
type __sync_val_compare_and_swap (type *ptr, type oldval type newval);
Das problem, das ich sehe, ist, dass der Rückgabewert von __sync_val_compare_and_swap ist der alte Wert von der *ptr. Um genau zu sein, ist es das Wert gesehen wurde, durch die Implementierung dieser Funktion einmal geeignete Speicher Barrieren war geschaffen worden. Ich hätten dies ausdrücklich zu bieten für die Tatsache, dass die zwischen den aufrufenden __sync_val_compare_and_swap und ausführen von Anweisungen, um die Durchsetzung der memory-Barriere der Wert von *ptr könnte leicht ändern.
Nun, wenn die Funktion zurückgibt, was kann ich tun, mit diesem return-Wert? Es gibt keinen Sinn, zu versuchen, zu vergleichen mit *ptr, da *ptr können jetzt geändert werden, in anderen threads. Ebenso vergleichen newval und *ptr nicht wirklich helfen (es sei denn, ich Sperre *ptr, die wahrscheinlich untergräbt meine Verwendung von atomics in den ersten Platz).
Also alle, die wirklich Links für mich zu tun, ist zu Fragen, ob der Rückgabewert == oldval, das ist effektiv (siehe unten für eine Einschränkung) mit der Frage, ob die swap-operation stattfand. So konnte ich gerade benutzt haben __sync_bool_compare_and_swap.
Dem VORBEHALT, ich habe gerade erwähnt, dass das nur subtiler Unterschied, den ich hier sehen kann, ist, dass dies nicht mir sagen, ob die swap aufgetreten ist oder nicht, es sagt mir nur, dass irgendwann, bevor die memory-Barriere wurde freigegeben *ptr hatte den gleichen Wert wie newval. Ich überlege mir die Möglichkeit, oldval == newval (obwohl ich würde kämpfen, um zu sehen, eine Art und Weise der Umsetzung, die effizient funktionieren, so dass Sie überprüfen könnten, diese Werte zuerst und nicht tauschen, wenn Sie waren die gleichen also ist es wohl ein strittiger Punkt). Allerdings kann ich nicht sehen, eine situation, wo die Kenntnis dieser Unterschied würde einen Unterschied machen, um mich an der call-site. In der Tat, ich kann mir nicht vorstellen, eine situation, wo ich würde oldval und newval gleich zu sein.
Meine Frage ist also:
Gibt es irgendeinen Anwendungsfall, in dem mit __sync_val_compare_and_swap und __sync_bool_compare_and_swap wäre nicht gleichwertig, d.h. ist es eine situation, wo man mehr Informationen als die anderen?
BEISEITE
Der Grund, warum ich war über dieses denken war, das fand ich eine Implementierung des __sync_val_compare_and_swap in Bezug auf sync_bool_compare_and_swap, die eine Rasse:
inline int32_t __sync_val_compare_and_swap(volatile int32_t* ptr, int32_t oldval, int32_t newval)
{
int32_t ret = *ptr;
(void)__sync_bool_compare_and_swap(ptr, oldval, newval);
return ret;
}
Die Rasse wird zur Speicherung von *ptr ret, *ptr könnte sich ändern, vor __sync_bool_compare_and_swap genannt wird. Es machte mir klar, dass ich es nicht scheinen, um einen sicheren Weg (ohne zusätzliche Barrieren oder sperren) Umsetzung __sync_val_compare_and_swap in Bezug auf sync_bool_compare_and_swap. Das gab mir zu denken, dass die ehemaligen müssen mit mehr "Informationen" als die letztere, aber nach meiner Frage, ich glaube nicht, dass es wirklich funktioniert.
Du hast Recht, dass der code in den "neben" buggy ist/hat einen schweren race-Bedingung. Ein retry-Schleife wird benötigt, um es zu korrigieren. Siehe meine Antwort.
InformationsquelleAutor Andrew Parker | 2015-04-28
Du musst angemeldet sein, um einen Kommentar abzugeben.
Den Betrieb zur Verfügung gestellt von
__sync_val_compare_and_swap
können immer durchgeführt werden, in Bezug auf__sync_bool_compare_and_swap
(und natürlich auch die andere Richtung ist natürlich möglich), so in Bezug auf macht die beiden sind gleichwertig. Die Umsetzung__sync_val_compare_and_swap
im Hinblick auf__sync_bool_compare_and_swap
ist nicht sehr effizient. Es sieht etwas aus wie:Die zusätzliche Arbeit erforderlich ist, weil Sie beobachten konnten Ausfall
__sync_bool_compare_and_swap
aber Lesen Sie dann einen neuen Wert aus*ptr
geschieht matcholdval
.Als für warum Sie vielleicht lieber die
__sync_val_compare_and_swap
Verhalten, den Wert, verursacht Ausfall kann Ihnen einen Ausgangspunkt, um den Vorgang zu wiederholen, effizienter oder könnte darauf hindeuten, eine sinnvolle Ursache des Fehlers für eine operation, die werden nicht "wiederholt". Als ein Beispiel, finden Sie den code fürpthread_spin_trylock
im musl libc (für die ich bin der Autor):http://git.musl-libc.org/cgit/musl/tree/src/thread/pthread_spin_trylock.c?id=afbcac6826988d12d9a874359cab735049c17500
Dort
a_cas
entspricht__sync_val_compare_and_swap
. In gewisser Weise ist dies ein dummes Beispiel, da es nur das speichern einer Verzweigung oder bedingten verschieben, indem Sie den alten Wert, aber es gibt andere Situationen, in denen mehrere alte Werte möglich sind, und wissen, die eine, die die operation scheitern Angelegenheiten.Denn eine funktionierende Umsetzung der
__sync_val_compare_and_swap
Sie muss einen Wert zurück, welcher den Spitzen-zu-Objekt hatte zu irgendeinem Zeitpunkt während der operation, ist nicht gleich dem argumentoldval
. Suche nach einem solchen Wertes ist unmöglich ohne Schleife, bis Sie es finden. Stellen Sie sich eine andere gleichzeitige thread schnell Umschalten (über gültige atomic-swaps) das Objekt Wert zwischenoldval
und einige sonst verborgene Wert.Ich sehe. Eine Letzte Sache, die mich beunruhigt. *ptr ändern könnte, bevor man es vergleichen kann mit oldval, aber es könnte sich ändern, zu einem anderen Wert, der nicht gleich oldval. Damit diese Umsetzung könnte einen Wert zurückgeben, die hatte keine Beziehung, warum der swap war erfolglos. Es ist eine pedantisch Punkt, aber ich Frage mich, ob es widerspricht der Spezifikation der Funktion. Zitat GCC-Seiten: "Die "val" - version gibt den Inhalt von *ptr vor der operation.". Diese Umsetzung würde nicht zurückkehren, den Inhalt von *ptr vor der op.
Was zählt als "vor der op" ist etwas, das Sie erhalten, zu entscheiden, wenn Sie ausfällt (und somit nicht die änderung der Spitzen-zu-Objekt). So lange, wie Sie zurück einigen anderen Wert als
oldval
dass*ptr
hatte irgendwann während des Gesprächs und sorgen für die richtige Sequenzierung aller anderen speichert/lädt relativ zu den speichern führte, dass der Wert, den Sie zurückgeben zu beachten, die Sie definieren können, der moment der "op", wie die Rückgabe der Funktion.Wenn auf der anderen Seite die compare-and-swap erfolgreich ist, dann ist der moment, der Betrieb ist eingeschränkt durch seine Sichtbarkeit in anderen threads, etc. aber dann ist es egal, denn du bist der Rückkehr
oldval
.InformationsquelleAutor R..