• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            西城

            指尖代碼,手上年華

            聯(lián)系 聚合 管理
              20 Posts :: 0 Stories :: 62 Comments :: 0 Trackbacks
            在看POCO網(wǎng)絡(luò)庫(kù)的時(shí)候,其中實(shí)現(xiàn)了一個(gè)singleton模式,提到了DCLP的不可行性。就去查閱了一下,
            找到了這篇文章。原文太長(zhǎng),將其意思大略整理如下。

            singleton差不多是所有設(shè)計(jì)模式中最為常見(jiàn)的一個(gè),但卻不是線程安全的。
            DCLP就是為了消除此缺點(diǎn)而設(shè)計(jì)出來(lái)的——Double Checked Locking Pattern。但卻仍然是
            不可靠的。


            一般的singleton實(shí)現(xiàn)為:
            // from the header file
            class Singleton {
            public:
            static Singleton* instance();

            private:
            static Singleton* pInstance;
            };
            // from the implementation file
            Singleton* Singleton::pInstance = 0;
            Singleton* Singleton::instance() {
            if (pInstance == 0) {                //Line 1
               pInstance=new Singleton;         //Line 2
            }
            return pInstance;
            }
            單線程模式下,這種方法工作的很好。但在多線程模式下卻是有問(wèn)題的。
            假設(shè)線程A進(jìn)入了instance函數(shù),執(zhí)行到Line 1,然后被掛起。當(dāng)它被掛起的時(shí)候,它
            剛測(cè)得pInstance是NULL,所以還沒(méi)有Singleton對(duì)象被創(chuàng)造出來(lái)。
            然后線程B進(jìn)入instance并且執(zhí)行到line1,發(fā)現(xiàn)pInstance是NULL,然后執(zhí)行下一句,創(chuàng)建了一個(gè)
            Singleton并且使pInstance指向它。然后返回pInstance.
            當(dāng)線程A繼續(xù)執(zhí)行的時(shí)候,它會(huì)執(zhí)行Line2,創(chuàng)建一個(gè)Singleton并使pInstance指向它,這就
            破壞了singleton的意義,因?yàn)閯?chuàng)建了兩個(gè)singleton.
            要想使其是線程安全的,需要在測(cè)試pInstance之間加一個(gè)lock.
            Singleton* Singleton::instance() {
            Lock lock;
            // acquire lock (params omitted for simplicity)
            if (pInstance == 0) {
            pInstance = new Singleton;
            }
            return pInstance;
            }
            // release lock 

            這樣有一個(gè)和很大的缺點(diǎn)——代價(jià)太高,每次訪問(wèn)都需要一個(gè)lock.但實(shí)際上,我們只需要在
            第一次創(chuàng)建的時(shí)候加一個(gè)鎖,而且應(yīng)該是instance第一次被調(diào)用的時(shí)候。如果在運(yùn)行時(shí)
            instance被調(diào)用了n次,我們只需要在第一次調(diào)用的時(shí)候加鎖就可以了。DCLP就是為了
            解決這個(gè)問(wèn)題而設(shè)計(jì)的--------------去掉那些不必要的LOCK。
            Singleton* Singleton::instance() {
            if (pInstance == 0) {
            // 1st test
            Lock lock;
            if (pInstance == 0) {
            // 2nd test
            pInstance = new Singleton;
            }
            }
            return pInstance;
            }
            DCLP在加鎖之前先測(cè)試pInstance是否為空,盡在其為NULL時(shí)才會(huì)需要一個(gè)LOCK,第二次測(cè)試也是
            必要的,因?yàn)橛锌赡芰硪粋€(gè)線程在第一次測(cè)試pInstance和請(qǐng)求LOCK時(shí)執(zhí)行了new.

            問(wèn)題之所在:
            pInstance=new Singleton;分為以下三步:
            1.分配內(nèi)存(sizeof(Singleton).
            2.在分配的內(nèi)存上創(chuàng)建一個(gè)Singleton對(duì)象。
            3.讓pInstance指向這塊內(nèi)存。問(wèn)題就在于編譯器不一定按照順序執(zhí)行這三步。 有時(shí)候編譯器會(huì)將
            第二步和第三步互換。此時(shí)情況可能如以下所示:
            Singleton* Singleton::instance() {
            if (pInstance == 0) {
            Lock lock;
            if (pInstance == 0) {
            pInstance =
            // Step 3
            operator new(sizeof(Singleton)); // Step 1
            // Step 2
            new (pInstance) Singleton;
            }
            }
            return pInstance;
            }
            在實(shí)際的DCLP代碼中,step2是可能拋出異常的,這時(shí)需要保證pInstance沒(méi)有變化(setp3未
            執(zhí)行)。所以一般并不能把step3移到step2之前,但有時(shí)候是可以的,比如說(shuō)step2并不拋出異
            常。
            現(xiàn)在如果線程A進(jìn)入instance,進(jìn)行第一次測(cè)試,請(qǐng)求了一個(gè)LOCK,然后執(zhí)行了step1和step3.
            然后被掛起。此時(shí)pInstance是NO-NULL,但是沒(méi)有singleton對(duì)象被創(chuàng)建出來(lái)。
            然后,線程B進(jìn)入instance,發(fā)現(xiàn)pInstance非空,然后將其返回,然后解引用,但是卻沒(méi)有對(duì)象。
            所以,DCLP只有在step1和step2在step3之前完成的情況下才能正常工作,但C/C++并不提供這樣的
            保證。
            posted on 2012-04-20 20:20 西城 閱讀(6763) 評(píng)論(7)  編輯 收藏 引用 所屬分類(lèi): C/C++

            Feedback

            # re: 為什么DCLP是不可行的?(1) 2012-04-21 10:36 runner.mei
            說(shuō)了半天,無(wú)非是想法要為 pInstance 加上 violate 修飾符嘛, 最新的 vc++ 和 gcc 都擴(kuò)展了 violate 的語(yǔ)義, 保證了它的原子性(Atomicity)和順序性(Ordering)了。DCLP是可行的  回復(fù)  更多評(píng)論
              

            # re: 為什么DCLP是不可行的?(1) 2012-04-21 10:39 runner.mei
            說(shuō)了半天,無(wú)非是想說(shuō)要為 pInstance 加上 violate 修飾符嘛, 最新的 vc++ 和 gcc 都擴(kuò)展了 violate 的語(yǔ)義, 保證了它的原子性(Atomicity)和順序性(Ordering)了。DCLP是可行的。
            已經(jīng)不是原創(chuàng)了,還分成幾篇,賺點(diǎn)擊。  回復(fù)  更多評(píng)論
              

            # re: 為什么DCLP是不可行的?(1) 2013-03-15 11:32 Eric.Tsai

            pInstance = new Singleton;
            改成
            Singleton *pTemp = new Singleton;
            pInstance = pTemp;
            不就可以避免了嗎? 還是我理解不夠透徹?  回復(fù)  更多評(píng)論
              

            # re: 為什么DCLP是不可行的?(1) 2013-03-15 11:44 Eric.Tsai
            看了原文才知道忘記"編譯器優(yōu)化了"@Eric.Tsai
              回復(fù)  更多評(píng)論
              

            久久亚洲高清观看| 伊人色综合久久天天人手人婷 | 久久综合狠狠色综合伊人| www.久久热| 天堂无码久久综合东京热| 国内精品伊人久久久影院| 久久99亚洲网美利坚合众国| 国产精品一区二区久久国产| 精品久久久久久无码中文野结衣| 一级a性色生活片久久无少妇一级婬片免费放| 久久综合色老色| 91超碰碰碰碰久久久久久综合 | 久久www免费人成看片| 久久国产免费观看精品| 亚洲欧美一区二区三区久久| 99久久人妻无码精品系列蜜桃| 日韩欧美亚洲综合久久影院Ds| 国产国产成人精品久久| 久久久久久国产精品无码下载| 久久国产成人午夜aⅴ影院| 99久久免费国产特黄| 久久精品国产亚洲AV忘忧草18| 久久996热精品xxxx| 国产V亚洲V天堂无码久久久| 久久综合九色综合网站| 欧美激情精品久久久久久久| 国产成人久久精品二区三区| 99久久精品毛片免费播放| 无码人妻久久一区二区三区免费丨| 合区精品久久久中文字幕一区| 精品水蜜桃久久久久久久| 国产福利电影一区二区三区久久老子无码午夜伦不 | 国产精品久久久久a影院| 久久se精品一区二区影院| 色综合色天天久久婷婷基地| 久久这里只精品国产99热| 色综合色天天久久婷婷基地| 国产午夜电影久久| 亚洲а∨天堂久久精品| 久久AV无码精品人妻糸列| 久久久久亚洲av无码专区|