Csharp/CSharp Tutorial/Thread/Custom Lock
A spin-lock
<source lang="csharp">/* Quote from Professional .NET Framework 2.0 (Programmer to Programmer) (Paperback) by Joe Duffy (Author)
- Paperback: 601 pages
- Publisher: Wrox (April 10, 2006)
- Language: English
- ISBN-10: 0764571354
- ISBN-13: 978-0764571350
- /
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime; using System.Runtime.rupilerServices; using System.Security; using System.Text; using System.Threading;
class SpinLock {
private int state; private EventWaitHandle available = new AutoResetEvent(false); // This looks at the total number of hardware threads available; if it"s // only 1, we will use an optimized code path private static bool isSingleProc = (Environment.ProcessorCount == 1); private const int outerTryCount = 5; private const int cexTryCount = 100; public void Enter(out bool taken) { // Taken is an out parameter so that we set it *inside* the critical // region, rather than returning it and permitting aborts to creep in. // Without this, the caller could take the lock, but not release it // because it didn"t know it had to. taken = false; while (!taken) { if (isSingleProc) { // Don"t busy wait on 1-logical processor machines; try // a single swap, and if it fails, drop back to EventWaitHandle. Thread.BeginCriticalRegion(); taken = Interlocked.rupareExchange(ref state, 1, 0) == 0; if (!taken) Thread.EndCriticalRegion(); } else { for (int i = 0; !taken && i < outerTryCount; i++) { // Tell the CLR we"re in a critical region; // interrupting could lead to deadlocks. Thread.BeginCriticalRegion(); // Try "cexTryCount" times to CEX the state variable: int tries = 0; while (!(taken = Interlocked.rupareExchange(ref state, 1, 0) == 0) && tries++ < cexTryCount) { Thread.SpinWait(1); } if (!taken) { // We failed to acquire in the busy spin, mark the end // of our critical region and yield to let another // thread make forward progress. Thread.EndCriticalRegion(); Thread.Sleep(0); } } } // If we didn"t acquire the lock, block. if (!taken) available.WaitOne(); } return; } public void Enter() { // Convenience method. Using this could be prone to deadlocks. bool b; Enter(out b); } public void Exit() { if (Interlocked.rupareExchange(ref state, 0, 1) == 1) { // We notify the waking threads inside our critical region so // that an abort doesn"t cause us to lose a pulse, (which could // lead to deadlocks). available.Set(); Thread.EndCriticalRegion(); } }
} public class MainClass {
public static void Main() { SpinLock sl1 = new SpinLock(); sl1.Enter(); try { Console.WriteLine("Acquired the spin lock"); } finally { sl1.Exit(); Console.WriteLine("Released the spin lock"); } }
}</source>
Acquired the spin lock Released the spin lock