Schreiben Sie eine Antwort für another question einige interessante Dinge kamen heraus und jetzt kann ich nicht verstehen, wie Interlocked.Increment(ref long value)
auf 32-Bit-Systemen funktioniert. Lassen Sie mich erklären.Atomic Inkrement von 64 Bit Variable auf 32 Bit Umgebung
Mutter InterlockedIncrement64
jetzt nicht verfügbar ist, wenn für 32-Bit-Umgebung kompiliert, OK, ist es sinnvoll, da in .NET können Sie nicht Speicher auszurichten, wie erforderlich und es kann aufgerufen werden, von verwalten dann ließ sie es.
In .NET wir Interlocked.Increment()
mit einer Referenz auf einen 64-Bit-Variable nennen können, wir haben noch keine Einschränkung über seine Ausrichtung (zum Beispiel in einer Struktur, wo wir auch FieldOffset
und StructLayout
verwenden können), sondern Dokumentation doesn Erwähnen Sie keine Einschränkung (AFAIK). Es ist Magie, es funktioniert!
Hans Passant bemerkt, dass Interlocked.Increment()
ist ein spezielle Methode von JIT-Compiler erkannt und es wird einen Aufruf an COMInterlocked::ExchangeAdd64() aussenden, die dann FastInterlockExchangeAddLong nennen, die ein Makro für InterlockedExchangeAdd64 ist die gleiche Einschränkungen von InterlockedIncrement64 teilt.
Jetzt bin ich perplex.
Vergessen Sie für eine Sekunde verwaltete Umgebung und gehen Sie zurück zu nativen. Warum kann InterlockedIncrement64
nicht funktionieren aber InterlockedExchangeAdd64
funktioniert? InterlockedIncrement64
ist ein Makro, wenn intrinsics nicht verfügbar sind und InterlockedExchangeAdd64
Werke dann kann es als Aufruf an InterlockedExchangeAdd64
implementiert werden ...
Lasst uns verwalteten zurück: wie ein Atom-64-Bit-Zuwachs auf 32-Bit-Systemen umgesetzt wird? Ich nehme an Satz "Diese Funktion ist atomisch in Bezug auf Aufrufe zu anderen verriegelten Funktionen" ist wichtig, aber immer noch sah ich keinen Code (danke Hans, um auf tiefere Implementierung hinweisen), es zu tun. Lassen Sie uns InterlockedExchangedAdd64
Implementierung von winbase.h holen, wenn intrinsics nicht verfügbar sind:
FORCEINLINE
LONGLONG
InterlockedExchangeAdd64(
_Inout_ LONGLONG volatile *Addend,
_In_ LONGLONG Value
)
{
LONGLONG Old;
do {
Old = *Addend;
} while (InterlockedCompareExchange64(Addend,
Old + Value,
Old) != Old);
return Old;
}
Wie kann es zum Lesen/Schreiben atomar sein?
Wer sagte, dass "InterlockedIncrement64" kann nicht funktionieren, aber "InterlockedExchangeAdd64" tut "? Ihre ursprüngliche Antwort war korrekt, wenn Sie sagen, dass verwalteter Code die systemeigenen Win32-APIs nicht direkt aufrufen kann und erwarten, dass alles funktioniert. Keiner von ihnen wird arbeiten. Sie müssen den verwalteten Helfer verwenden. Die Implementierung des verwalteten Helfers ist jetzt systemeigener Code und ruft die native Funktion auf. Da die Makros und Intrinsics zur Kompilierungszeit aufgelöst werden, zählt die Bitterkeit der CLR. –
Ja, aber 32-Bit-JIT wird InterlockedExchangeAdd64 aufrufen, das dieselben Einschränkungen (in nativ) wie InterlockedIncrement64 aufweist. Was ich nicht verstanden habe, ist, wie es gemacht werden kann (wegen der Speicherausrichtung, wenn nach verwaltetem Code aufgerufen wird). Implementierung auf 32-Bit verwendet InterlockedCompareExchange64, die ... hmmm .... möglicherweise nicht atomare (zum Schreiben von Ergebnis zurück ...) –
* "Wie kann es atomare zum Lesen/Schreiben sein?" * Die Dokumentation für 'InterlockedExchangeAdd64' Hinweise "* Diese Funktion generiert eine vollständige Speicherbarriere (oder einen Zaun), um sicherzustellen, dass die Speichervorgänge der Reihe nach ausgeführt werden." * Beachten Sie, dass die oben gezeigte Implementierung "InterlockedCompareExchange64" aufruft. Bei 32-Bit-Builds gibt dies eine CMPXCHG8B-Anweisung mit einem LOCK-Präfix aus. Dies stellt sicher, dass der Befehl atomar ausgeführt wird. Sie erhalten niemals einen gesperrten Lesevorgang ohne Schreibsperre, daher ist das Schreiben des Ziels atomar. –