日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

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

發(fā)布時(shí)間:2025/7/14 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入浅出多线程系列之四:简单的同步 lock 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1: 考慮下下面的代碼:

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

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

?

這段代碼是非線程安全的,假設(shè)有兩個(gè)線程A,BA,B都執(zhí)行到了Go方法的if判斷中,假設(shè)_val2=1.所以?xún)蓚€(gè)線程A,B都通過(guò)if判斷,

A執(zhí)行了Console.WriteLine方法,然后退出if語(yǔ)句,執(zhí)行_val2=0,此時(shí)_val2=0.

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

?

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

??????? 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;
????????????}
????????}

此時(shí)線程AB都只能有一個(gè)可以獲得_locker鎖,所以只能有一個(gè)線程來(lái)執(zhí)行lock塊的代碼。

C#Lock關(guān)鍵字實(shí)際上是Monitor.Enter,Monitor.Exit的縮寫(xiě)。例如上面的代碼和下面的等價(jià)。

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

如果在調(diào)用Monitor.Exit之前沒(méi)有調(diào)用Monitor.Enter,則會(huì)拋出一個(gè)異常。

?

不知道大家注意到?jīng)]有,Monitor.Enter Try 方法之間可能會(huì)拋出異常。

例如在線程上調(diào)用Abort,或者是OutOfMemoryException

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

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

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

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

?

2:選擇同步對(duì)象。

Monitor.Enter方法的參數(shù)是一個(gè)object類(lèi)型,所以任何對(duì)象都可以是同步對(duì)象,考慮下下面的代碼:

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

    23:鎖定thistype對(duì)象,會(huì)導(dǎo)致無(wú)法控制鎖的邏輯,并且它很難保證不死鎖和頻繁的阻塞,在相同進(jìn)程中鎖定type對(duì)象會(huì)穿越應(yīng)用程序域。

    4:由于字符串駐留機(jī)制,所以也不要鎖定string,關(guān)于這點(diǎn),請(qǐng)大家去逛一逛老A的博客。

    ?

    3:嵌套鎖:

    同一個(gè)線程可以多次鎖定同一對(duì)象。例如

    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);

    ?

    當(dāng)一個(gè)線程使用一個(gè)鎖調(diào)用另一方法的時(shí)候,嵌套鎖就非常的有用。例如:

    ?????? 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的鎖。

    程序進(jìn)入了死鎖狀態(tài),兩個(gè)線程都在等待對(duì)方釋放自己等待的鎖。?

    CLR作為一個(gè)獨(dú)立宿主環(huán)境,它不像SQL Server一樣,它沒(méi)有自動(dòng)檢測(cè)死鎖機(jī)制,也不會(huì)結(jié)束一個(gè)線程來(lái)破壞死鎖。死鎖的線程會(huì)導(dǎo)致部分線程無(wú)限的等待。

    ?

    下篇文章會(huì)介紹一些其他同步構(gòu)造。

    ?

    ?

    參考資料:

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

    CLR Via C# 3.0

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/LoveJenny/archive/2011/05/23/2053604.html

    總結(jié)

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

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。