Meine zwei Cent auf SpinLock in .Net

Stellen Sie sich eine Situation vor, in der ein Thread versucht, Zugriff auf eine gemeinsam genutzte Ressource zu erhalten, die Ressource jedoch bereits gesperrt ist. Daher muss der Thread warten, bis die Sperre aufgehoben wird. Hier kommt die Thread-Synchronisation ins Spiel. Die Thread-Synchronisierung wird verwendet, um zu verhindern, dass mehrere Threads gleichzeitig auf eine gemeinsam genutzte Ressource zugreifen. Das Microsoft .NET Framework bietet Unterstützung für eine Reihe von Synchronisationsprimitiven, mit denen das Thread-Verhalten gesteuert und Race-Bedingungen vermieden werden können. Mutex und Spinlock sind zwei beliebte Synchronisationsmechanismen, mit denen der Zugriff auf eine gemeinsam genutzte Ressource synchronisiert wird.

Ein SpinLock ist eine Alternative zum Blockieren der Synchronisation. SpinLock (auch als "Busy Waiting" bezeichnet) ist ein Mechanismus, mit dem ein Thread, der versucht, eine Sperre zu erhalten, in einer Schleife warten lässt, bis er Zugriff auf die Ressource erhält. Beachten Sie, dass SpinLock im Vergleich zu Mutex schneller arbeiten kann, da die Kontextumschaltung reduziert ist. Sie sollten SpinLocks jedoch nur verwenden, wenn der kritische Abschnitt einen minimalen Arbeitsaufwand ausführen soll, dh das SpinLock wird für einen sehr kurzen Zeitraum gehalten. SpinLocks werden normalerweise in symmetrischen Multiprozessorsystemen bevorzugt, um anstelle von Kontextwechseln ständig die Verfügbarkeit einer Ressource abzufragen.

Was ist SpinLock und warum wird es benötigt?

SpinLock führt viel Warten durch und kann eine bessere Leistung bieten, wenn es in Mehrkernsystemen verwendet wird, insbesondere wenn es billig ist, in einer Schleife zu warten und eine Ressource zu bündeln, anstatt sie zu blockieren. Dies ist besonders hilfreich, wenn die Sperrhaltezeiten von kurzer Dauer sind. Mit anderen Worten, Sie können SpinLock in Mehrkernsystemen nutzen, um den Aufwand für die Kontextumschaltung zu verringern, wenn die Zeit innerhalb des kritischen Abschnitts gering ist. Ein kritischer Abschnitt kann als Datenstruktur oder Ressource definiert werden, die von mehreren Threads gemeinsam genutzt wird, aber nur ein Thread kann zu einem bestimmten Zeitpunkt darauf zugreifen.

Es sollte beachtet werden, dass das längere Halten von SpinLock einfach eine Verschwendung der Systemressourcen darstellt und die Leistung der Anwendung beeinträchtigt. Wenn Sie erwarten, dass die Blockierung von erheblicher Dauer ist, sollte SpinLock niemals verwendet werden. Verwenden Sie SpinLock im Wesentlichen nur, wenn die Sperrhaltezeiten relativ kurz sind.

SpinLock wird normalerweise verwendet, wenn mit Interrupts gearbeitet wird, um in einer Schleife zu warten, bis die Ressource verfügbar ist. SpinLock bewirkt nicht, dass der Thread vorbelegt wird, sondern dreht sich weiter, bis die Sperre für die Ressource aufgehoben wird.

Programmieren von SpinLock in .Net

Beachten Sie, dass ein SpinLock in .Net als Struktur definiert ist, dh aus Leistungsgründen als Werttyp definiert ist. Wenn Sie eine SpinLock-Instanz übergeben, sollten Sie sie daher als Referenz und nicht als Wert übergeben. In diesem Abschnitt werden wir untersuchen, wie wir SpinLock in .Net programmieren können. Um SpinLock in .Net zu implementieren, müssen Sie die im System.Threading-Namespace verfügbare SpinLock-Klasse nutzen.

Die folgende Codeliste zeigt, wie Sie SpinLock in .Net verwenden können.

SpinLock spinLock = new SpinLock (true);

bool isLocked = false;

try

{

spinLock.Enter (ref isLocked);

// Write your usual code here

}

finally

{

if (isLocked)

   spinLock.Exit();

}

SpinWait

Beachten Sie, dass SpinWait wie SpinLock auch eine Struktur und keine Klasse ist. Ähnlich wie bei SpinLock können Sie mit SpinWait sperrfreien Synchronisationscode schreiben, der sich eher drehen als blockieren kann. SpinWait kann verwendet werden, um den Ressourcenverbrauch zu reduzieren, indem für 10 Iterationen nach der CPU ein CPU-intensives Spinnen durchgeführt wird, das die Steuerung durch Aufrufen von Thread.Yield und Thread.Sleep ergibt. Mit anderen Worten, SpinWait kann verwendet werden, um das CPU-intensive Drehen auf eine feste Anzahl von Iterationen zu beschränken. In der MSDN heißt es: "System.Threading.SpinWait ist ein einfacher Synchronisationstyp, den Sie in Szenarien auf niedriger Ebene verwenden können, um die teuren Kontextwechsel und Kernelübergänge zu vermeiden, die für Kernelereignisse erforderlich sind."

Um SpinWait in Ihrem Code zu verwenden, können Sie entweder die statische SpinUntil () -Methode der SpinWait-Struktur nutzen oder die nicht statische SpinOnce () -Methode nutzen. Das folgende Codefragment zeigt, wie SpinWait verwendet werden kann.

SpinWait spinWait = new SpinWait();

bool shouldSpin;

while (!shouldSpin)

{

   Thread.MemoryBarrier(); spinWait.SpinOnce();

}