lock學習篇(上)

why?

當我們使用線程的時候,效率最高的方式當然是異步,即各個線程同時運行,其間不相互依賴和等待。
但當不同的線程都需要訪問某個資源的時候,就需要同步機制了,也就是說當對同一個資源進行讀寫的時候,
我們要使該資源在同一時刻只能被一個線程操作,以確保每個操作都是有效即時的,也即保證其操作的原子性。
lock是C#中最常用的同步方式,格式爲lock(objectA){codeB} 。

lock (objectA) { codeB}
看似簡單,實際上有三個意思,這對於適當地使用它至關重要:
1.objectA被lock了嗎?沒有則由我來lock,否則一直等待,直至objectA被釋放。
2.lock以後在執行codeB的期間其他線程不能調用codeB,也不能使用objectA。
3.執行完codeB之後釋放objectA,並且codeB可以被其他線程訪問。

https://www.cnblogs.com/apsnet/archive/2012/07/08/2581475.html

即爲了保證資源的一致性

when?

需要該資源在同一時刻只能被一個線程操作

how?

通過加鎖來確保在操作完成之前不會被第二個資源進行訪問

場景一:

存在生產與售出方法
兩個方法同時操作庫存

code:

// 生產數量
public int MakeCount { get; set; }

// 售出數量
public int SellCount { get; set; }

//庫存
private int Products { get; set; }

//產品製造
public void Make(int num)
{
    Products += num;
    MakeCount += num;
    Console.WriteLine($"生產了{num}個{ProductName},當前產品總數爲:{Products}");
}

//產品售出
public void Sell(int num)
{
  if (Products < num)
  {
    Console.WriteLine($"庫存不足,當前庫存爲:{Products}");
    return;
  }

  Products -= num;
  SellCount += num;
  Console.WriteLine($"售出了{num}個{ProductName},當前產品總數爲:{Products}");
}

result:

  總生產數量: 11,總售出數量: 8,當前庫存: 3,實際庫存: 3
  總生產數量: 31,總售出數量: 29,當前庫存: 1,實際庫存: 2
  總生產數量: 51,總售出數量: 47,當前庫存: 1,實際庫存: 4
  總生產數量: 73,總售出數量: 67,當前庫存: 3,實際庫存: 6
  總生產數量: 93,總售出數量: 71,當前庫存: 19,實際庫存: 22
  總生產數量: 97,總售出數量: 71,當前庫存: 23,實際庫存: 26

解決方法: 在操作數據時加鎖,保證在同一時間僅有一個線程操作此數據

private int _products;

public int Products
{
  get
  {
    return this._products;
  }
  set
  {
    lock (this)
      this._products = value;
  }
}

note1: 單方法操作,不會導致數據異常

note2: 當執行時間越短,觸發數據異常機遇越小

lock是如何執行的?

lock <==> Monitor

lock (this)
{
  _products = value;
}

//等價於:

bool lockTaken = false;
try
{
  Monitor.Enter(this, ref lockTaken);
  _products = value;
}
finally
{
  if (lockTaken) Monitor.Exit(this);
}

https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.monitor?view=netframework-4.8

什麼是Monitor?/Monitord有什麼作用?

提供同步訪問對象的機制。

Monitor的使用

code:

//庫存
private int goods { get; set; }

//生產量
private int make { get; set; }

//銷售量
private int sell { get; set; }

public void Make()
{
  if (Monitor.TryEnter(_lock, TimeSpan.FromMilliseconds(1000)))
  {
    try
    {
      goods++;
      make++;
      Console.WriteLine($"製造了一個產品,當前產品數量:{goods}");
      ////System.Threading.SynchronizationLockException:“Object synchronization method was called from an unsynchronized block of code.”
      //爲避免生產過量,生產完後會提醒銷售售出
      Monitor.Pulse(_lock);
    }
    finally
    {
      Monitor.Exit(_lock);
    }
  }
  else
  {
    Console.WriteLine("生成失敗");
  }
}

public void Sell()
{
  if (Monitor.TryEnter(_lock, TimeSpan.FromMilliseconds(1000)))
  {
    while (goods <= 0) //庫存不足
    {
      //System.Threading.SynchronizationLockException:“Object synchronization method was called from an unsynchronized block of code.”
      //同步方法不能在非同方方法中調用
      if (!Monitor.Wait(_lock, TimeSpan.FromMilliseconds(1000))) //等待生成
      {
        Console.WriteLine("庫存不足!");
        return;
      }
    }

    sell++;
    goods--;
    Console.WriteLine($"售出了一個產品,當前庫存:{goods}");
  }
  else
  {
    Console.WriteLine($"購買失敗");
  }
}

public void Show()
{
  Console.WriteLine($"當前庫存:{goods},生產量:{make},銷售量:{sell},實際庫存:{sell - make}");
  if (make - sell != goods) throw new Exception("銷售異常!");
}

note

  1. 同步索引塊是.NET中解決對象同步問題的基本機制
  2. 這個對象肯定要是引用類型,值類型可不可呢?值類型可以裝箱啊!你覺得可不可以?但也不要用值類型,因爲值類型多次裝箱後的對象是不同的,會導致無法鎖定;
  3. 不要鎖定this,儘量使用一個沒有意義的Object對象來鎖;
  4. 不要鎖定一個類型對象,因類型對象是全局的;
  5. 不要鎖定一個字符串,因爲字符串可能被駐留,不同字符對象可能指向同一個字符串;
  6. 不要使用[System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.Synchronized)],這個可以使用在方法上面,保證方法同一時刻只能被一個線程調用。她實質上是使用lock的,如果是實例方法,會鎖定this,如果是靜態方法,則會鎖定類型對象;

confirm

通常,應避免鎖定 public 類型,否則實例將超出代碼的控制範圍。

常見的結構 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 違反此準則:

如果實例可以被公共訪問,將出現 lock (this) 問題。
如果 MyType 可以被公共訪問,將出現 lock (typeof (MyType)) 問題。
由於進程中使用同一字符串的任何其他代碼將共享同一個鎖,所以出現 lock(“myLock”) 問題。

ext

https://www.cnblogs.com/anding/p/5301754.html

https://www.cnblogs.com/carsonzhu/p/7446953.html


author:monster

since:5/7/2019 2:02:24 PM

direction:lock

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章