日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入浅出多线程系列之四:简单的同步 lock

發布時間:2025/7/14 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入浅出多线程系列之四:简单的同步 lock 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1: 考慮下下面的代碼:

class?ThreadUnsafe
????{
????????
static?int?_val1?=?1,?_val2?=?1;

????????
internal?static?void?Go()
????????{
????????????
if?(_val2?!=?0)
????????????{
????????????????Console.WriteLine(_val1?
/_val2);
????????????}
????????????_val2?
=?0;
????????}
????}

?

這段代碼是非線程安全的,假設有兩個線程A,BA,B都執行到了Go方法的if判斷中,假設_val2=1.所以兩個線程A,B都通過if判斷,

A執行了Console.WriteLine方法,然后退出if語句,執行_val2=0,此時_val2=0.

但是此時線程B才剛剛執行到Console.WriteLine方法,而此時_val2=0.所以你有可能會得到一個divide by zero 的異常。

?

為了保證線程安全,我們可以使用Lock關鍵字,例如:

??????? static?readonly?object?_locker?=?new?object();
????????
static?int?_val1?=?1,?_val2?=?1;

????????
internal?static?void?Go()
????????{
????????????
lock?(_locker)
????????????{
????????????????
if?(_val2?!=?0)
????????????????{
????????????????????Console.WriteLine(_val1?
/?_val2);
????????????????}
????????????????_val2?
=?0;
????????????}
????????}

此時線程AB都只能有一個可以獲得_locker鎖,所以只能有一個線程來執行lock塊的代碼。

C#Lock關鍵字實際上是Monitor.Enter,Monitor.Exit的縮寫。例如上面的代碼和下面的等價。

??????????? Monitor.Enter(_locker);
????????????
try
????????????{
????????????????
if?(_val2?!=?0)
????????????????{
????????????????????Console.WriteLine(_val1?
/?_val2);
????????????????}
????????????????_val2?
=?0;
????????????}
????????????
finally?{?Monitor.Exit(_locker);?}

如果在調用Monitor.Exit之前沒有調用Monitor.Enter,則會拋出一個異常。

?

不知道大家注意到沒有,Monitor.Enter Try 方法之間可能會拋出異常。

例如在線程上調用Abort,或者是OutOfMemoryException

為了解決這個問題CLR 4.0提供了Monitor.Enter的重載,增加了lockTaken 字段,當Monitor.Enter成功獲取鎖之后,lockTaken就是True,否則為False

我們可以將上面的代碼改成下面的版本。

??????????? bool?lockTaken?=?false;
????????????
try
????????????{
????????????????Monitor.Enter(_locker,?
ref?lockTaken);
????????????????
//?Do?something..
????????????}
????????????
finally{?
????????????????
if(lockTaken)?{
????????????????????Monitor.Exit(_locker);
????????????????}
????????????}

Monitor也提供了TryEnter方法,并且可以傳遞一個超時時間。如果方法返回True,則代表獲取了鎖,否則為false

?

2:選擇同步對象。

Monitor.Enter方法的參數是一個object類型,所以任何對象都可以是同步對象,考慮下下面的代碼:

  • int i=5; lock(i){}??       //鎖定值類型
  • lock(this){}           //鎖定this對象
  • lock(typeof(Product)){}      //鎖定type對象。
  • string str="dddd"; lock(str){}?? //鎖定字符串
  • 1:鎖定值類型會將值類型進行裝箱,所以Monitor.Enter進入的是一個對象,但是Monitor.Exit()退出的是另一個不同的對象。

    23:鎖定thistype對象,會導致無法控制鎖的邏輯,并且它很難保證不死鎖和頻繁的阻塞,在相同進程中鎖定type對象會穿越應用程序域。

    4:由于字符串駐留機制,所以也不要鎖定string,關于這點,請大家去逛一逛老A的博客。

    ?

    3:嵌套鎖:

    同一個線程可以多次鎖定同一對象。例如

    lock(locker)
    ????
    lock(locker)
    ????????
    lock(locker)
    ????????{
    ????????????
    //?do?something
         }

    或者是:

    Monitor.Enter(locker);?Monitor.Enter(locker);?Monitor.Enter(locker);
    //Do?something.
    Monitor.Exit(locker);?Monitor.Exit(locker);?Monitor.Exit(locker);

    ?

    當一個線程使用一個鎖調用另一方法的時候,嵌套鎖就非常的有用。例如:

    ?????? static?readonly?object?_locker?=?new?object();

    ????????
    static?void?Main()
    ????????{
    ????????????
    lock?(_locker)
    ????????????{?
    ????????????????AnotherMethod();
    ????????????}
    ????????}

    ????????
    static?void?AnotherMethod()
    ????????{
    ????????????
    lock?(_locker){?//dosomething;}
    ????????}

    ?

    4:死鎖:

    先看下面的代碼:

    ??????? static?object?locker1?=?new?object();
    ????????
    static?object?locker2?=?new?object();

    ????????
    public?static?void?MainThread()
    ????????{
    ????????????
    new?Thread(()?=>
    ????????????????{
    ????????????????????
    lock?(locker1)?? //獲取鎖locker1
    ????????????????????{
    ????????????????????????Thread.Sleep(
    1000);
    ????????????????????????
    lock?(locker2) //嘗試獲取locker2
    ????????????????????????{
    ????????????????????????????Console.WriteLine(
    "locker1,locker2");
    ????????????????????????}
    ????????????????????}
    ????????????????}).Start();
    ????????????
    lock?(locker2) //獲取鎖locker2
    ????????????{
    ????????????????Thread.Sleep(
    1000);
    ????????????????
    lock?(locker1) //嘗試獲取locker1
    ????????????????{
    ????????????????????Console.WriteLine(
    "locker2,locker1");
    ????????????????}
    ????????????}
    ????????}

    在這里

    主線程先獲取locker2的鎖,然后sleep,接著嘗試獲取locker1的鎖。

    副線程先獲取locker1的鎖,然后sleep,接著嘗試獲取locker2的鎖。

    程序進入了死鎖狀態,兩個線程都在等待對方釋放自己等待的鎖。?

    CLR作為一個獨立宿主環境,它不像SQL Server一樣,它沒有自動檢測死鎖機制,也不會結束一個線程來破壞死鎖。死鎖的線程會導致部分線程無限的等待。

    ?

    下篇文章會介紹一些其他同步構造。

    ?

    ?

    參考資料:

    http://www.albahari.com/threading/

    CLR Via C# 3.0

    ?

    轉載于:https://www.cnblogs.com/LoveJenny/archive/2011/05/23/2053604.html

    總結

    以上是生活随笔為你收集整理的深入浅出多线程系列之四:简单的同步 lock的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。