以下測試的概念是對同一個記憶體空間做++和--,正確的結果應該為0,但若沒有Lock或Interlocked機制,不同執行緒會更改同一塊記憶體的值,譬如threadOne執行了++,尚未執行--,而threadTwo此時又執行++,這時候就會出現誤差,導致最終結果錯誤。
執行10次的結果,Counter每次都不一樣,但CounterWithLock及CounterNoLock則每次都為0。
以下為程式代碼:
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
/** *******************
* Thread的Lock機制
* ********************/
//沒有使用Lock
var c = new Counter();
var threadOne = new Thread(() => CountNumbers(c));
var threadTwo = new Thread(() => CountNumbers(c));
var threadThree = new Thread(() => CountNumbers(c));
threadOne.Start();
threadTwo.Start();
threadThree.Start();
threadOne.Join();
threadTwo.Join();
threadThree.Join();
Console.WriteLine($"Total is {c.Count}");
//使用Lock
var c1 = new CounterWithLock();
threadOne = new Thread(() => CountNumbers(c1));
threadTwo = new Thread(() => CountNumbers(c1));
threadThree = new Thread(() => CountNumbers(c1));
threadOne.Start();
threadTwo.Start();
threadThree.Start();
threadOne.Join();
threadTwo.Join();
threadThree.Join();
Console.WriteLine($"Total is {c1.Count}");
//使用Interlocked
var c2 = new CounterNoLock();
threadOne = new Thread(() => CountNumbers(c2));
threadTwo = new Thread(() => CountNumbers(c2));
threadThree = new Thread(() => CountNumbers(c2));
threadOne.Start();
threadTwo.Start();
threadThree.Start();
threadOne.Join();
threadTwo.Join();
threadThree.Join();
Console.WriteLine($"Total is {c2.Count}");
}
static void CountNumbers(CountBase cnt)
{
for (int i = 0; i <= 100000; i++)
{
cnt.Increase();
cnt.Descrease();
}
}
}
abstract class CountBase
{
public abstract void Increase();
public abstract void Descrease();
}
class Counter : CountBase
{
private int _count;
public int Count { get { return _count; } }
public override void Increase()
{
_count++;
}
public override void Descrease()
{
_count--;
}
}
class CounterWithLock : CountBase
{
private int _count;
public int Count { get { return _count; } }
private readonly object _SyncRoot = new Object();
public override void Increase()
{
//lock的對象必須是object(但不要lock string),不能是int, long等數值型
//若為public函數,不要lock(this),不然很容易造成deadlock
lock (_SyncRoot)
{
_count++;
}
}
public override void Descrease()
{
lock (_SyncRoot)
{
_count--;
}
}
}
class CounterNoLock : CountBase
{
private int _count;
public int Count { get { return _count; } }
public override void Increase()
{
Interlocked.Increment(ref _count);
}
public override void Descrease()
{
Interlocked.Decrement(ref _count);
}
}
}
沒有留言:
張貼留言