日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

c#多線程同步[MethodImpl(MethodImplOptions.Synchronized)]、lock(this)與lock(typeof(...))

 lawrence0303 2009-04-16

[原創(chuàng)][MethodImpl(MethodImplOptions.Synchronized)]、lock(this)與lock(typeof(...))

 

 

 

對(duì)于稍微有點(diǎn)經(jīng)驗(yàn)的.NET開(kāi)發(fā)人員來(lái)說(shuō),倘若被問(wèn)及如何保持線程同步,我想很多人都能說(shuō)好好幾種。在眾多的線程同步的可選方式中,加鎖無(wú)疑是最為常用的。如果僅僅是基于方法級(jí)別的線程同步,使用System.Runtime.CompilerServices.MethodImplAttribute無(wú)疑是最為簡(jiǎn)潔的一種方式。MethodImplAttribute可以用于instance method,也可以用于static method。當(dāng)在某個(gè)方法上標(biāo)注了MethodImplAttribute,并指定MethodImplOptions.Synchronized參數(shù),可以確保在不同線程中運(yùn)行的該方式以同步的方式運(yùn)行。我們幾天來(lái)討論MethodImplAttribute(MethodImplOptions.Synchronized)和lock的關(guān)系。

一、提出結(jié)論

在進(jìn)行討論之前,我先提出下面3個(gè)結(jié)論:

1、[MethodImplAttribute(MethodImplOptions.Synchronized)]仍然采用加鎖的機(jī)制實(shí)現(xiàn)線程的同步。

2、如果[MethodImplAttribute(MethodImplOptions.Synchronized)]被應(yīng)用到instance method,相當(dāng)于對(duì)當(dāng)前實(shí)例加鎖。

3、如果[MethodImplAttribute(MethodImplOptions.Synchronized)]被應(yīng)用到static method,相當(dāng)于當(dāng)前類(lèi)型加鎖

二、基于instance method的線程同步

為了驗(yàn)證我們上面提出的結(jié)論,我作了一個(gè)小小的例子。在一個(gè)console application中定義了一個(gè)class:SyncHelper,其中定義了一個(gè)方法Execute。打印出方法執(zhí)行的時(shí)間,并休眠當(dāng)前線程模擬一個(gè)耗時(shí)的操作:

class SyncHelper
{
    public void Execute()
    {
        Console.WriteLine("Excute at {0}", DateTime.Now);
        Thread.Sleep(5000);
    }
}

在入口Main方法中,創(chuàng)建SyncHelper對(duì)象,通過(guò)一個(gè)System.Threading.Timer對(duì)象實(shí)現(xiàn)每隔1s調(diào)用該對(duì)象的Execute方法:

class Program
{
    static void Main(string[] args)
    {
        SyncHelper helper = new SyncHelper();
        Timer timer = new Timer(
        delegate
        {
            helper.Execute();
        }, null, 0, 1000);

        Console.Read();

    }
}

 

 

 

 

 

 

 

 

 

由于Timer對(duì)象采用異步的方式進(jìn)行調(diào)用,所以雖然Execute方法的執(zhí)行時(shí)間是5s,但是該方法仍然是每隔1s被執(zhí)行一次。這一點(diǎn)從最終執(zhí)行的結(jié)果可以看出:

image

為了讓同一個(gè)SyncHelper對(duì)象的Execute方法同步執(zhí)行,我們?cè)贓xecute方法上添加了如下一個(gè)MethodImplAttribute:

[MethodImpl(MethodImplOptions.Synchronized)]
public void Execute()
{
    Console.WriteLine("Excute at {0}", DateTime.Now);
    Thread.Sleep(5000);
}

 

 

 

從如下的輸出結(jié)果我們可以看出Execute方法是以同步的方式執(zhí)行的,因?yàn)閮纱螆?zhí)行的間隔正式Execute方法執(zhí)行的時(shí)間:

image

在一開(kāi)始我們提出的結(jié)論中,我們提到“如果[MethodImplAttribute(MethodImplOptions.Synchronized)]被應(yīng)用到instance method,相當(dāng)于對(duì)當(dāng)前實(shí)例加鎖”。說(shuō)得直白一點(diǎn):[MethodImplAttribute(MethodImplOptions.Synchronized)] = lock(this)。我們可以通過(guò)下面的實(shí)驗(yàn)驗(yàn)證這一點(diǎn)。為此,在SyncHelper中定義了一個(gè)方法LockMyself。在此方法中對(duì)自身加鎖,并持續(xù)5s中,并答應(yīng)加鎖和解鎖的時(shí)間。

public void LockMyself()
{
   lock (this)
    {
        Console.WriteLine("Lock myself at {0}", DateTime.Now);
        Thread.Sleep(5000);
        Console.WriteLine("Unlock myself at {0}", DateTime.Now);
    }
}

我們?cè)贛ain()中以異步的方式(通過(guò)創(chuàng)建新的線程的方式)調(diào)用該方法:

static void Main(string[] args)
{
    SyncHelper helper = new SyncHelper();

    Thread thread = new Thread(
        delegate()
        {           

             helper.LockMyself();

        });
    thread.Start();
    Timer timer = new Timer(
    delegate
    {
        helper.Execute();
    }, null, 0, 1000);

    Console.Read();
}

 

 

 

 

 

 

結(jié)合我們的第二個(gè)結(jié)論想想最終的輸出會(huì)是如何。由于LockMyself方法是在另一個(gè)線程中執(zhí)行,我們可以簡(jiǎn)單講該方法的執(zhí)行和Execute的第一個(gè)次執(zhí)行看作是同時(shí)的。但是MethodImplAttribute(MethodImplOptions.Synchronized)]果真是通過(guò)lock(this)的方式實(shí)現(xiàn)的話,Execute必須在等待LockMyself方法執(zhí)行結(jié)束將對(duì)自身的鎖釋放后才能得以執(zhí)行。也就是說(shuō)LockMyself和第一次Execute方法的執(zhí)行應(yīng)該相差5s。而輸出的結(jié)果證實(shí)了這點(diǎn):

image

三、基于static method的線程同步

討論完再instance method上添加MethodImplAttribute(MethodImplOptions.Synchronized)]的情況,我們相同的方式來(lái)討論倘若一樣的MethodImplAttribute被應(yīng)用到static方法,又會(huì)使怎樣的結(jié)果。

我們先將Execute方法上的MethodImplAttribute注釋掉,并將其改為static方法:

//[MethodImpl(MethodImplOptions.Synchronized)]
public static void Execute()
{
    Console.WriteLine("Excute at {0}", DateTime.Now);
    Thread.Sleep(5000);
}

 

 

 

 

 

 

 

 

在Main方法中,通過(guò)Timer調(diào)用該static方法:

static void Main(string[] args)
{
    Timer timer = new Timer(
    delegate
    {
        SyncHelper.Execute();
    }, null, 0, 1000);

    Console.Read();
}

毫無(wú)疑問(wèn),Execute方法將以1s的間隔異步地執(zhí)行,最終的輸出結(jié)果如下:

image

然后我們將對(duì)[MethodImpl(MethodImplOptions.Synchronized)]的注釋取消:

[MethodImpl(MethodImplOptions.Synchronized)]
public static void Execute()
{
    Console.WriteLine("Excute at {0}", DateTime.Now);
    Thread.Sleep(5000);
}

最終的輸出結(jié)果證實(shí)了Execute將會(huì)按照我們期望的那樣以同步的方式執(zhí)行,執(zhí)行的間隔正是方法執(zhí)行的時(shí)間:

image

我們回顧一下第三個(gè)結(jié)論:“如果[MethodImplAttribute(MethodImplOptions.Synchronized)]被應(yīng)用到static method,相當(dāng)于當(dāng)前類(lèi)型加鎖”。為了驗(yàn)證這個(gè)結(jié)論,在SyncHelper中添加了一個(gè)新的static方法:LockType。該方法對(duì)SyncHelper tpye加鎖,并持續(xù)5s中,在加鎖和解鎖是打印出當(dāng)前時(shí)間:

public static void LockType()
{
    lock (typeof(SyncHelper))
    {
        Console.WriteLine("Lock SyncHelper type at {0}", DateTime.Now);
        Thread.Sleep(5000);
        Console.WriteLine("Unlock SyncHelper type at {0}", DateTime.Now);
    }
}

在Main中,像驗(yàn)證instance method一樣,創(chuàng)建新的線程執(zhí)行LockType方法:

static void Main(string[] args)
{
    Thread thread = new Thread(
        delegate()
        {
            SyncHelper.LockType();
        });
    thread.Start();

    Timer timer = new Timer(
    delegate
    {
        SyncHelper.Execute();
    }, null, 0, 1000);

    Console.Read();
}

如果基于static method的[MethodImplAttribute(MethodImplOptions.Synchronized)]是通過(guò)對(duì)Type進(jìn)行加鎖實(shí)現(xiàn)。那么通過(guò)Timer輪詢(xún)的第一個(gè)Execute方法需要在LockType方法執(zhí)行完成將對(duì)SyncHelper type的鎖釋放后才能執(zhí)行。所以如果上述的結(jié)論成立,將會(huì)有下面的輸出:

image

四、總結(jié)

對(duì)于加鎖來(lái)說(shuō),鎖的粒度的選擇顯得至關(guān)重要。在不同的場(chǎng)景中需要選擇不同粒度的鎖。如果選擇錯(cuò)誤往往會(huì)對(duì)性能造成很到的影響,嚴(yán)重時(shí)還會(huì)引起死鎖。就拿[MethodImplAttribute(MethodImplOptions.Synchronized)]來(lái)說(shuō),如果開(kāi)發(fā)人員對(duì)它的實(shí)現(xiàn)機(jī)制不了解,很有可能使它lock(this)或者lock(typeof(…))并存,造成方法得不到及時(shí)地執(zhí)行。

最后說(shuō)一句題外話,因?yàn)樽址v留機(jī)制的存在,切忌對(duì)string進(jìn)行加鎖。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多