iT邦幫忙

1

[C#] lock-執行緒資源鎖定 防止多個執行緒同時執行共用程式段

c#
  • 分享至 

  • xImage
  •  

實務上我們可能會遇到這樣的需求:
需要避免多個執行緒同時占用同一個資源,來防止一些bug產生。
這時候C#中的lock可以幫上很大的忙~
lock可以把一段程式碼鎖定,讓這一段程式同時只容許一個執行緒執行,
若後續有其他執行緒也要執行這段程式,就必須等到lock解除後才能進入。

下面寫一個簡單的小程式來模擬沒有使用lock時會出現的程式bug:

  • Controller
  private string testStringc = "";
  private static string testStringd = ""; 

  [HttpGet]
  public string TEST(string a)
  {
     try
     {
        testStringc = a;
        testStringd = a;

        Thread.Sleep(5000);
        return testStringc + " , " + testStringd;
     }
     catch
     {
        return "ERROR!";
     }
  }

首先分別宣告一個普通的string testStringc,和一個靜態類別的string testStringd
然後跑一個簡單的function TEST
這個function將testStringc和testStringd的值都指定為變數a後,
等待5秒,再return testStringc和testStringd的值。

在只有單一個執行緒的情況下,當指定a的值為123時,
可以正常的跑出預期的結果123,123
https://ithelp.ithome.com.tw/upload/images/20221027/20149099gPr6sM07Q2.jpg

但如果另開一個無痕瀏覽器,並在5秒內分別在兩個瀏覽器視窗執行TEST時,
(無痕瀏覽器這邊指定a的值為456)
我們有機會看到先執行的那一個執行緒出現下面的結果:
https://ithelp.ithome.com.tw/upload/images/20221027/20149099KCbhtDcIzV.jpg

因為testStringd是靜態類別的關係,導致執行結果變成123,456了。
若要避免這個問題,可以將lock加入,把程式碼改寫為:

  • Controller
 private static object lockObject = new object();
  private string testStringc = "";
  private static string testStringd = ""; 

  [HttpGet]
  public string TEST(string a)
  {
     try
     {
       lock (lockObject)
        {
          testStringc = a;
          testStringd = a;

          Thread.Sleep(5000);
          return testStringc + " , " + testStringd;
        }
     }
     catch
     {
        return "ERROR!";
     }
  }

宣告一個靜態物件lockObject作為lock的目標,
在執行TEST時,lock住lockObject,直到執行完return後,lock才會解除,
這樣改寫後,當第二個執行緒要執行TEST時,會因為lock的緣故,
必須等到第一個執行緒完成return後,才能接續執行TEST,
就不會出現第一個執行緒的執行結果被覆蓋的問題了~

lock在使用上最需要注意的是:避免使用在共用的物件上,以防死鎖的狀況,
另外執行時間越短越好,因為過多的資源獨佔會造成效能方面的問題。

參考文章
https://learn.microsoft.com/zh-tw/dotnet/csharp/language-reference/statements/lock
https://dotblogs.com.tw/yc421206/2011/01/07/20624
以及公司前輩熱心分享


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言