短時間鎖定的情況下,自旋鎖(spinlock)更快。(因為自旋鎖本質上不會讓線程休眠,而是一直循環嘗試對資源訪問,直到可用。所以自旋鎖線程被阻塞時,不進行線程上下文切換,而是空轉等待。對於多核CPU而言,減少了切換線程上下文的開銷,從而提高了性能。)
以下是簡單實例(並行執行10000次,每次想list中添加一項。執行完后准確的結果應該是10000):
foo1:使用系統的自旋鎖。
foo4:不使用鎖。結果必然是不正確的。
foo5:通過Interlocked實現自旋鎖。
1 public class SpinLockDemo 2 { 3 int i = 0; 4 List<int> li = new List<int>(); 5 SpinLock sl = new SpinLock(); 6 int signal = 0; 7 8 public void Execute() 9 { 10 foo1(); 11 //li.ForEach((t) => { Console.WriteLine(t); }); 12 Console.WriteLine("Li Count - Spinlock: "+li.Count); 13 li.Clear(); 14 foo4(); 15 Console.WriteLine("Li Count - Nolock: " + li.Count); 16 li.Clear(); 17 foo5(); 18 Console.WriteLine("Li Count - Customized Spinlock: " + li.Count); 19 20 } 21 22 public void foo1() 23 { 24 Parallel.For(0, 10000, r => 25 { 26 bool gotLock = false; //釋放成功 27 try 28 { 29 sl.Enter(ref gotLock); //進入鎖 30 //Thread.Sleep(100); 31 if (i == 0) 32 { 33 i = 1; 34 li.Add(r); 35 i = 0; 36 } 37 } 38 finally 39 { 40 if (gotLock) sl.Exit(); //釋放 41 } 42 43 }); 44 } 45 46 public void foo4() 47 { 48 Parallel.For(0, 10000, r => 49 { 50 if (i == 0) 51 { 52 i = 1; 53 li.Add(r); 54 i = 0; 55 } 56 }); 57 } 58 59 public void foo5() 60 { 61 Parallel.For(0, 10000, r => 62 { 63 while (Interlocked.Exchange(ref signal, 1) != 0)//加自旋鎖 64 {} 65 li.Add(r); 66 Interlocked.Exchange(ref signal, 0); //釋放鎖 67 }); 68 69 } 70 71 public void foo6() 72 { 73 //Console.WriteLine(i); 74 //Task.Run(new Action(foo2)).ContinueWith(new Action<Task>(t => 75 //{ 76 // Console.WriteLine("foo2 completed: " + i); 77 //})); 78 //Console.WriteLine(i); 79 //Task.Run(new Action(foo2)).ContinueWith(new Action<Task>(t => 80 //{ 81 // Console.WriteLine("foo3 completed: " + i); 82 //})); 83 //Console.WriteLine(i); 84 } 85 public void foo2() 86 { 87 bool lck = false; 88 sl.Enter(ref lck); 89 Thread.Sleep(100); 90 ++i; 91 if (lck) sl.Exit(); 92 } 93 94 public void foo3() 95 { 96 bool lck = false; 97 sl.Enter(ref lck); 98 ++i; 99 if (lck) sl.Exit(); 100 } 101 }
結果如下: