第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問題,去搜搜看,總會(huì)有你想問的

具有不同線程安全模式的System.Lazy <T>

具有不同線程安全模式的System.Lazy <T>

慕妹3146593 2019-12-06 09:38:03
.NET 4.0的System.Lazy <T>類通過枚舉LazyThreadSafetyMode提供了三種線程安全模式,我將其總結(jié)為:LazyThreadSafetyMode.None - 不是線程安全的。LazyThreadSafetyMode.ExecutionAndPublication - 只有一個(gè)線程同時(shí)將嘗試創(chuàng)造潛在價(jià)值。創(chuàng)建成功后,所有等待線程將獲得相同的值。如果在創(chuàng)建過程中發(fā)生未處理的異常,則將在每個(gè)等待的線程上將其重新拋出,在每次后續(xù)訪問基礎(chǔ)值的嘗試中將對其進(jìn)行緩存和重新拋出。LazyThreadSafetyMode.PublicationOnly - 多個(gè)并發(fā)線程將嘗試創(chuàng)造潛在價(jià)值,但第一個(gè)成功將決定傳遞給所有線程值。如果在創(chuàng)建過程中發(fā)生未處理的異常,則不會(huì)對其進(jìn)行緩存,并且并發(fā)訪問和隨后嘗試訪問基礎(chǔ)值的嘗試將重試創(chuàng)建,并且可能會(huì)成功。我想要一個(gè)延遲初始化的值,該值遵循略有不同的線程安全規(guī)則,即:只有一個(gè)并發(fā)線程將嘗試創(chuàng)建基礎(chǔ)值。創(chuàng)建成功后,所有等待線程將獲得相同的值。如果在創(chuàng)建過程中發(fā)生未處理的異常,它將在每個(gè)等待的線程上重新拋出,但不會(huì)被緩存,并且隨后嘗試訪問基礎(chǔ)值的嘗試將重試創(chuàng)建,并且可能會(huì)成功。因此,與LazyThreadSafetyMode.ExecutionAndPublication的主要區(qū)別在于,如果創(chuàng)建時(shí)“先行嘗試”失敗,則可以在以后重新嘗試。是否存在提供這些語義的現(xiàn)有(.NET 4.0)類,還是我必須自己滾動(dòng)?如果我自己動(dòng)手,是否存在一種聰明的方法來重用實(shí)現(xiàn)中的現(xiàn)有Lazy <T>以避免顯式的鎖定/同步?注意:對于一個(gè)用例,想象一下“創(chuàng)建”可能是昂貴的并且容易出現(xiàn)間歇性錯(cuò)誤,例如涉及從遠(yuǎn)程服務(wù)器獲取大量數(shù)據(jù)。我不想進(jìn)行多次并發(fā)嘗試來獲取數(shù)據(jù),因?yàn)樗鼈兒芸赡苋渴』蛉砍晒?。但是,如果它們失敗了,我希望稍后再試?
查看完整描述

3 回答

?
白板的微信

TA貢獻(xiàn)1883條經(jīng)驗(yàn) 獲得超3個(gè)贊

我嘗試的是達(dá)林更新后的答案版本,但沒有我指出的比賽條件...警告,我不確定這最終是否完全擺脫了比賽條件。


private static int waiters = 0;

private static volatile Lazy<object> lazy = new Lazy<object>(GetValueFromSomewhere);

public static object Value

{

    get

    {

        Lazy<object> currLazy = lazy;

        if (currLazy.IsValueCreated)

            return currLazy.Value;


        Interlocked.Increment(ref waiters);


        try

        {

            return lazy.Value;


            // just leave "waiters" at whatever it is... no harm in it.

        }

        catch

        {

            if (Interlocked.Decrement(ref waiters) == 0)

                lazy = new Lazy<object>(GetValueFromSomewhere);

            throw;

        }

    }

}

更新:我以為發(fā)布此消息后發(fā)現(xiàn)了比賽情況。該行為實(shí)際上應(yīng)該是可以接受的,只要您對一個(gè)罕見的情況感到滿意,即Lazy<T>在另一個(gè)線程已經(jīng)從成功的快速返回之后,某個(gè)線程拋出了一個(gè)從慢速觀察到的異常Lazy<T>(將來的請求將全部成功)。


waiters = 0

t1:一直運(yùn)行到Interlocked.Decrement(waiters= 1)之前

t2:進(jìn)入并運(yùn)行到Interlocked.Increment(waiters= 1)之前

t1:進(jìn)行Interlocked.Decrement并準(zhǔn)備覆蓋(waiters= 0)

t2:一直運(yùn)行到Interlocked.Decrement(waiters= 1)之前

t1:lazy用新的覆蓋(稱為lazy1)(waiters= 1)

t3:進(jìn)入并在lazy1(waiters= 2)處阻止

t2:是否執(zhí)行Interlocked.Decrement(waiters= 1)

t3:從lazy1(waiters現(xiàn)在不相關(guān))獲取并返回值

t2:拋出異常

我無法提出一系列導(dǎo)致比“該線程在另一個(gè)線程產(chǎn)生成功結(jié)果之后引發(fā)異常”更糟糕的事情的事件。


Update2:聲明lazy為volatile確保所有讀者立即都能看到受保護(hù)的覆蓋。有些人(包括我自己在內(nèi))看到volatile并立即想到“好吧,可能是使用不正確”,他們通常是正確的。這就是我在這里使用它的原因:在上面示例中的事件序列中,t3仍然可以讀取舊的,lazy而不是lazy1如果它位于lazy.Valuet1修改lazy為包含的那一刻之前l(fā)azy1。 volatile防止這種情況,以便下次嘗試可以立即開始。


我還提醒自己,為什么我腦子里有這樣的話:“低鎖并發(fā)編程很難,只需使用C#lock語句!??!” 我一直在寫原始答案。


Update3:只是更改了Update2中的一些文本,指出了volatile必要的實(shí)際情況- Interlocked此處使用的操作顯然是在當(dāng)今重要的CPU架構(gòu)上全屏實(shí)現(xiàn)的,而不是我最初只是假設(shè)的半屏實(shí)現(xiàn)的,因此volatile保護(hù)的范圍比我原來想象的要窄得多。


查看完整回答
反對 回復(fù) 2019-12-06
?
長風(fēng)秋雁

TA貢獻(xiàn)1757條經(jīng)驗(yàn) 獲得超7個(gè)贊

只有一個(gè)并發(fā)線程將嘗試創(chuàng)建基礎(chǔ)值。創(chuàng)建成功后,所有等待線程將獲得相同的值。如果在創(chuàng)建過程中發(fā)生未處理的異常,它將在每個(gè)等待的線程上重新拋出,但不會(huì)被緩存,并且隨后嘗試訪問基礎(chǔ)值的嘗試將重試創(chuàng)建,并且可能會(huì)成功。


由于Lazy不支持該功能,因此您可以嘗試自行滾動(dòng):


private static object syncRoot = new object();

private static object value = null;

public static object Value

{

    get

    {

        if (value == null)

        {

            lock (syncRoot)

            {

                if (value == null)

                {

                    // Only one concurrent thread will attempt to create the underlying value.

                    // And if `GetTheValueFromSomewhere` throws an exception, then the value field

                    // will not be assigned to anything and later access

                    // to the Value property will retry. As far as the exception

                    // is concerned it will obviously be propagated

                    // to the consumer of the Value getter

                    value = GetTheValueFromSomewhere();

                }

            }

        }

        return value;

    }

}

更新:


為了滿足您對傳播到所有等待讀取器線程的相同異常的要求:


private static Lazy<object> lazy = new Lazy<object>(GetTheValueFromSomewhere);

public static object Value

{

    get

    {

        try

        {

            return lazy.Value;

        }

        catch

        {

            // We recreate the lazy field so that subsequent readers

            // don't just get a cached exception but rather attempt

            // to call the GetTheValueFromSomewhere() expensive method

            // in order to calculate the value again

            lazy = new Lazy<object>(GetTheValueFromSomewhere);


            // Re-throw the exception so that all blocked reader threads

            // will get this exact same exception thrown.

            throw;

        }

    }

}


查看完整回答
反對 回復(fù) 2019-12-06
  • 3 回答
  • 0 關(guān)注
  • 1021 瀏覽

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)