帶着問題去思考!你們好。
今天咱們來了解下什麼是線程同步?安全
首先咱們先知道這些概念和一些類;多線程
咱們都知道確保當一個線程使用某些資源的時候,同時其餘線程沒法使用該資源。這引入一個概念是共享資源。ide
多個線程同時使用共享對象會形成不少問題。同步線程使得對共享對象的操做可以以正確的順序執行是很是重要的。spa
首先經過一個加減例子瞭解下lock處理操作系統
public abstract class CounterBase { public abstract void Increment(); public abstract void Decrement(); } public class Counter:CounterBase { public int Count { get;private set; } public override void Decrement() { Count++; } public override void Increment() { Count--; } } public class CounterLock : CounterBase { private readonly object _synclock = new object(); public int Count { get; private set; } public override void Decrement() { lock(_synclock) { Count++; } } public override void Increment() { lock (_synclock) { Count--; } } } static void Main(string[] args) { #region 多線程鎖 Console.WriteLine("Incorrect counter"); var c = new Counter(); var t1 = new Thread(() => TestCount(c)); var t2= new Thread(() => TestCount(c)); var t3 = new Thread(() => TestCount(c)); t1.Start(); t2.Start(); t3.Start(); t1.Join(); t2.Join(); t3.Join(); Console.WriteLine("Total count:{0}",c.Count); Console.WriteLine("-----------"); Console.WriteLine("Correct counter"); var c1 = new CounterLock(); t1 = new Thread(() => TestCount(c1)); t2 = new Thread(() => TestCount(c1)); t3 = new Thread(() => TestCount(c1)); t1.Start(); t2.Start(); t3.Start(); t1.Join(); t2.Join(); t3.Join(); Console.WriteLine("Total count:{0}", c1.Count); #endregion } static void TestCount(CounterBase c) { for (int i = 0; i < 1000; i++) { c.Increment(); c.Decrement(); } }
咱們知道,最終結果應該是0;線程
由於第一個線程獲得count爲10增長爲11,第二個線程獲得的值是11並增長爲12.第一個線程獲得count爲12,可是遞減操做發生前,第二個線程獲得的值也是12,。而後第一個線程將12遞減11並保存count中,同時第二個線程進行了一樣的操做,結果咱們進行了兩次遞增操做可是隻有一次遞減操做。這是競爭條件(race condition)code
1:請儘可能避免使用共享對象對象
2:必須是共享的狀態時候,使用原子操做。一個操做只佔一個量子的時間,一次完成。這說明只有當前操做完成後,其餘線程才能執行其餘操做,避免死鎖,和使用鎖blog
3:使用不一樣方式來協調線程資源
執行基本的原子操做
不用阻塞線程就可避免競爭條件
public class CounterLock : CounterBase { public int Count { get; private set; } public int _count; public override void Decrement() { Interlocked.Decrement(ref _count); } public override void Increment() { Interlocked.Increment(ref _count); } }
咱們修改CounterLock,再來看看結果
咱們可能會獲得0,可是最終會獲得一些不肯定的非0.第一個例子是線程不安全的。第二個例子中,咱們藉助Interlocked類,無需鎖定任何對象便可獲取正確結果。Interlocked提供了Increment.Decrement和Add基於數學操做的原子方法,編寫Counter類時無需使用鎖、
Mutex類
const string MutexName = "CSharpThreadingCookbook"; static void Main(string[] args) { using (var m=new Mutex(false,MutexName)) { if(!m.WaitOne(TimeSpan.FromSeconds(5),false)) { Console.WriteLine("Second instance is running!"); } else { Console.WriteLine("Running!"); Console.ReadLine(); m.ReleaseMutex(); } } }
程序啓動,定義一個指定名稱的互斥量,設置initialOwner標誌爲false,這意味着若是互斥量已經被建立,則容許程序獲取該互斥量。若是沒有得到互斥量,程序則簡單顯示Running
在運行一樣一個程序,則會在5秒種內嘗試得到互斥量,若是此時在第一個程序中按下任意鍵,第二個程序則會開始執行。然而若是保持等待5秒,第二個程序沒法得到該互斥量