2010-12-21 5 views
6

Okay, ich frage das Gleiche wie this deleted question, aber ich frage es direkter.Wie kann ich zwei Zeiger unter Windows atomar vertauschen?

Ich habe zwei Zeigervariablen in zwei Instanzen der gleichen Klasse. Ich würde gerne den Inhalt dieser Variablen (nicht was sie angeben, sondern nur die Variablen selbst) atomar vertauschen.

Ich würde gerne Schlösser zu vermeiden, wenn überhaupt möglich.

Wie mache ich das?

EDIT: Um die drei Zillion "InterlockedExchangePointer" Antworten, lesen Sie bitte zuerst die MSDN docs. InterlockedExchangePointer tauscht den Wert eines Zeigerziels mit einem Wert auf dem Stapelregister aus. Es (selbst) tauscht nicht zwei Zeiger in Speicherorten aus.

+7

Ich glaube nicht, dass es eine nicht-locking X86-Anweisung gibt, um den Inhalt von zwei Speicheradressen zu tauschen. Ohne CPU-Unterstützung wäre es schwierig, eine solche Funktion zu implementieren. Gibt es Garantien für die Hinweise? (ZB sind sie immer im Speicher benachbart? Wenn ja, könnten Sie einen 8-Byte- oder 16-Byte-Vergleich/Austausch in einer Schleife verwenden.) –

+0

@James: Da Sie das Gleiche über jeden Kommentar gepostet haben: 'int * p1 = ein Wert; int * p2 = irgendein anderer Wert; p2 = InterlockedExchangePointer (p1, p2); würde genau das tun. Obwohl darunter ein kritischer Abschnitt verwendet wird, bin ich mir nicht sicher, ob es mit der Notwendigkeit, Sperren vollständig zu vermeiden, übereinstimmt. –

+1

wow, viele Leute geben die falsche Antwort ...das sollte eine Interviewfrage sein ':-)' – rubenvb

Antwort

13

Ich werde auf ein Bein gehen und sagen, dass Sie ein Schloss benötigen und dass es keine Lock-Free-Lösung für den allgemeinen Fall für dieses Problem gibt.

Sie müssten von zwei Adressen lesen und auf beide Adressen alle atomar schreiben. Soweit ich weiß, kann X86 nur Daten von einer einzigen Speicheradresse und einem Register atomar austauschen. Ich denke nicht, dass es möglich ist, den Inhalt von zwei Speicheradressen auszutauschen.

Wenn Sie Beschränkungen festlegen können, wo die Zeiger sind, können Sie dies tun. Wenn Sie beispielsweise garantieren können, dass die Zeiger im Speicher nebeneinander liegen, können Sie einen 64- oder 128-Bit-Vergleich/Austausch in einer Schleife verwenden.

Es mag Lösungen für andere einfache Fälle geben, aber ich glaube nicht, dass Sie eine lockfreie Lösung für den allgemeinen Fall finden werden.

+0

+1 - sieht aus wie keine 'WindowsApi :: AutoArray :: Swap' Threadsicherheit für mich. (Denn jeder Zeiger rechtfertigt NICHT den Aufwand, einen kritischen Abschnitt zu warten!) –

+1

+1 Ich denke, das ist richtig. –

+0

Eine begrenzte Auswahl an Prozessoren verfügt über einen doppelten Vergleichs- und Austauschvorgang (DCAS/CAS2). Sie können auch CMPXCHG16B (doppelte Breite) zu einem ähnlichen Effekt verwenden. Dies ist nicht "allgemein", da viele CPUs diese Anweisungen nicht unterstützen, aber auf denen, die dies tun können. DCAS ist auf Motorola 68k, CMPXCHG16B ist auf 64-Bit-Intel und * neuere * 64-Bit-AMD, aber nicht ältere. _InterlockedCompareExchange128 implementiert dies als ein Array von 64-Bit-Zeigern, die als atomares 128-Bit-Feld ausgewertet werden, explodiert jedoch, wenn der Prozessor den Befehl nicht unterstützt. – Lisa

-2

Überprüfen Sie die x86-Prozessor Anweisungen Xchg, wenn sie tun, was Sie wollen, dann können Sie sie in Inline-Assembly-Funktion umbrechen. Alle Prozessor-Einzelbefehle sind garantiert atomar.

+0

Diese Antwort hat die gleichen Probleme wie InterlockedExchangePointer Antworten. –

+0

+1 weil das * if * in * wenn sie tun, was du willst * gibt false zurück, deshalb wirst du keinen einfachen Weg finden, dies zu tun –

+0

@Pete: * Wenn * das "if" false zurückgibt, dann dies Beantworte meine Frage nicht, auch wenn sie nicht sachlich falsch ist. –

2

Sie suchen eine atomare, verblockte Version von swap.

Nach meinem Wissen gibt es keine Möglichkeit, dies nur mit Windows-API-Primitiven und ohne explizites Sperren zu tun. Die verschiedenen Interlocked Funktionen, die von anderen empfohlen werden, funktionieren nicht, da nur einer der übergebenen Parameter geändert wird. Sie möchten beide ändern.

Ich könnte auch darauf hinweisen, dass die Interlocked Funktionen nur miteinander verzahnt sind. Wenn Sie über einen weiteren Code verfügen, der einen dieser Zeiger aktualisiert, aber Interlocked nicht verwendet, ist Ihr Code nicht mehr sicher. Ich bin mir sicher, dass dir das klar ist, aber ich dachte, ich würde es erwähnen.

Soweit ich weiß, müssen Sie eine Bibliothek verwenden oder Ihren eigenen Code schreiben, um damit umzugehen.

Verwandte Themen