青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

每天早晨叫醒你的不是鬧鐘,而是夢(mèng)想

  C++博客 :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
  62 Posts :: 0 Stories :: 5 Comments :: 0 Trackbacks

常用鏈接

留言簿(1)

我參與的團(tuán)隊(duì)

搜索

  •  

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

http://www.c-view.org/journal/006/gp_aa.htm 


并不是我故意想弄糟你的心情,但是在這期專欄里,我們將討論多線程編程這一話題。正如上一期Generic里所說(shuō)的,編寫(xiě)異常安全(exception-safe)的程序是非常困難的,但是和編寫(xiě)多線程程序比起來(lái),那簡(jiǎn)直就是兒戲。  

多線程的程序是出了名的難編寫(xiě)、難驗(yàn)證、難調(diào)試、難維護(hù),這通常是件苦差事。不正確的多線程程序可能可以運(yùn)行很多年也不出一點(diǎn)錯(cuò),直到滿足某些臨界的條件時(shí),才出現(xiàn)意想不到的奇怪錯(cuò)誤。  

不用說(shuō),編寫(xiě)多線程程序的程序員需要使用可能得到的所有幫助。這期專欄將專注于討論競(jìng)爭(zhēng)條件(race conditions)——這通常是多線程程序中各種麻煩的根源——深入了解它并提供一些工具來(lái)防止競(jìng)爭(zhēng)。令人驚異的是,我們將讓編譯器盡其所能來(lái)幫助你做這些事。

僅僅一個(gè)不起眼的關(guān)鍵字 
盡管C和C++標(biāo)準(zhǔn)對(duì)于線程都明顯的“保持沉默”,但它們以volatile關(guān)鍵字的形式,確實(shí)為多線程保留了一點(diǎn)特權(quán)。  

就象大家更熟悉的const一樣,volatile是一個(gè)類(lèi)型修飾符(type modifier)。它是被設(shè)計(jì)用來(lái)修飾被不同線程訪問(wèn)和修改的變量。如果沒(méi)有volatile,基本上會(huì)導(dǎo)致這樣的結(jié)果:要么無(wú)法編寫(xiě)多線程程序,要么編譯器失去大量?jī)?yōu)化的機(jī)會(huì)。下面我們來(lái)一個(gè)個(gè)說(shuō)明。  

考慮下面的代碼:  

 1class Gadget
 2{
 3public:
 4    void Wait()
 5    {
 6        while (!flag_)
 7        {
 8            Sleep(1000); // sleeps for 1000 milliseconds
 9        }

10    }

11    void Wakeup()
12    
13        flag_ = true
14    }

15    
16private
17    bool flag_; 
18}
;
19
20


 
上面代碼中Gadget::Wait的目的是每過(guò)一秒鐘去檢查一下flag_成員變量,當(dāng)flag_被另一個(gè)線程設(shè)為true時(shí),該函數(shù)才會(huì)返回。至少這是程序作
者的意圖,然而,這個(gè)Wait函數(shù)是錯(cuò)誤的.假設(shè)編譯器發(fā)現(xiàn)Sleep(1000)是調(diào)用一個(gè)外部的庫(kù)函數(shù),它不會(huì)改變成員變量flag_,那么編譯器就可
以斷定它可以把flag_緩存在寄存器中,以后可以訪問(wèn)該寄存器來(lái)代替訪問(wèn)較慢的主板上的內(nèi)存。這對(duì)于單線程代碼來(lái)說(shuō)是一個(gè)很好的優(yōu)化,但
是在現(xiàn)在這種情況下,它破壞了程序的正確性:當(dāng)你調(diào)用了某個(gè)Gadget的Wait函數(shù)后,即使另一個(gè)線程調(diào)用了Wakeup,Wait還是會(huì)一直循環(huán)下去。
這是因?yàn)閒lag_的改變沒(méi)有反映到緩存它的寄存器中去。編譯器的優(yōu)化未免有點(diǎn)太……樂(lè)觀了。

在大多數(shù)情況下,把變量緩存在寄存器中是一個(gè)非常有價(jià)值的優(yōu)化方法,如果不用的話很可惜。C和C++給你提供了顯式禁用這種緩存優(yōu)化的機(jī)會(huì)。
如果你聲明變量是使用了volatile修飾符,編譯器就不會(huì)把這個(gè)變量緩存在寄存器里——每次訪問(wèn)都將去存取變量在內(nèi)存中的實(shí)際位置。這樣你
要對(duì)Gadget的Wait/Wakeup做的修改就是給flag_加上正確的修飾:  

class Gadget 
{ 
public: 
    ... as above ... 
private: 
    volatile bool flag_; 
}; 



大多數(shù)關(guān)于volatile的原理和用法的解釋就到此為止,并且建議你用volatile修飾在多個(gè)線程中使用的原生類(lèi)型變量。然而,你可以用volatile
做更多的事,因?yàn)樗巧衿娴腃++類(lèi)型系統(tǒng)的一部分。




把volatile用于自定義類(lèi)型 
volatile修飾不僅可以用于原生類(lèi)型,也可以用于自定義類(lèi)型。這時(shí)候,volatile修飾方式類(lèi)似于const(你也可以對(duì)一個(gè)類(lèi)型同時(shí)使用const
和volatile).

與const不同,volatile的作用對(duì)于原生類(lèi)型和自定義類(lèi)型是有區(qū)別的。就是說(shuō),原生類(lèi)型有volatile修飾時(shí),仍然支持它們的各種操作(加、
乘、賦值等等),然而對(duì)于class來(lái)說(shuō),就不是這樣。舉例來(lái)說(shuō),你可以把一個(gè)非volatile的int的值賦給一個(gè)volatile的int,但是你不能把一
個(gè)非volatile的對(duì)象賦給一個(gè)volatile對(duì)象。 

讓我們舉個(gè)例子來(lái)說(shuō)明自定義類(lèi)型的volatile是怎么工作的。  
class Gadget

{
public:
    void Foo() volatile;
    void Bar();
    ...
private:
    String name_;
    int state_;
};
...

Gadget regularGadget;
volatile Gadget volatileGadget;



如果你認(rèn)為volatile對(duì)于對(duì)象來(lái)說(shuō)沒(méi)有什么作用的話,那你可要大吃一驚了。  
volatileGadget.Foo(); // ok, volatile fun called for 
                          // volatile object 
regularGadget.Foo();  // ok, volatile fun called for 
                          // non-volatile object 
volatileGadget.Bar(); // error! Non-volatile function called for 
                          // volatile object! 

從沒(méi)有volatile修飾的類(lèi)型到相應(yīng)的volatile類(lèi)型的轉(zhuǎn)換是很平常的。但是,就象const一樣,你不能反過(guò)來(lái)把volatile類(lèi)型轉(zhuǎn)換為非volatile類(lèi)型。你必須用類(lèi)型轉(zhuǎn)換運(yùn)算符:  
Gadget& ref = const_cast<Gadget&>;(volatileGadget); 
ref.Bar(); // ok 

一個(gè)有volatile修飾的類(lèi)只允許訪問(wèn)其接口的一個(gè)子集,這個(gè)子集由類(lèi)的實(shí)現(xiàn)者來(lái)控制。用戶只有用const_cast才可以訪問(wèn)這個(gè)類(lèi)型的全部接口。而且,象const一樣,類(lèi)的volatile屬性會(huì)傳遞給它的成員(例如,volatileGadget.name_和volatileGadget.state_也是volatile變量)。

volatile,臨界區(qū)和競(jìng)爭(zhēng)條件 
多線程程序中最簡(jiǎn)單也是最常用的同步機(jī)制要算是mutex(互斥對(duì)象)了。一個(gè)mutex只提供兩個(gè)基本操作:Acquire和Release。一旦某個(gè)線程調(diào)用了Acquire,其他線程再調(diào)用Acquire時(shí)就會(huì)被阻塞。當(dāng)這個(gè)線程調(diào)用Release后,剛才阻塞在Acquire里的線程中,會(huì)有一個(gè)且僅有一個(gè)被喚醒。換句話說(shuō),對(duì)于一個(gè)給定的mutex,只有一個(gè)線程可以在Acquire和Release調(diào)用之間獲取處理器時(shí)間。在Acquire和Release調(diào)用之間執(zhí)行的代碼叫做臨界區(qū)(critical section)。(Windows的用語(yǔ)可能會(huì)引起一點(diǎn)混亂,因?yàn)閃indows把mutex本身叫做臨界區(qū),而Windows的mutex實(shí)際上指進(jìn)程間的mutex。如果把它們分別叫作線程mutex和進(jìn)程mutex可能會(huì)好些。)  

Mutex是用來(lái)避免數(shù)據(jù)出現(xiàn)競(jìng)爭(zhēng)條件。根據(jù)定義,所謂競(jìng)爭(zhēng)條件就是這樣一種情況:多個(gè)線程對(duì)數(shù)據(jù)產(chǎn)生的作用要依賴于線程的調(diào)度順序的。當(dāng)兩個(gè)線程競(jìng)相訪問(wèn)同一數(shù)據(jù)時(shí),就會(huì)發(fā)生競(jìng)爭(zhēng)條件。因?yàn)橐粋€(gè)線程可以在任意一個(gè)時(shí)刻打斷其他線程,數(shù)據(jù)可能會(huì)被破壞或者被錯(cuò)誤地解釋。因此,對(duì)數(shù)據(jù)的修改操作,以及有些情況下的訪問(wèn)操作,必須用臨界區(qū)保護(hù)起來(lái)。在面向?qū)ο蟮木幊讨校@通常意味著你在一個(gè)類(lèi)的成員變量中保存一個(gè)mutex,然后在你訪問(wèn)這個(gè)類(lèi)的狀態(tài)時(shí)使用這個(gè)mutex。  

多線程編程高手看了上面兩個(gè)段落,可能已經(jīng)在打哈欠了,但是它們的目的只是提供一個(gè)準(zhǔn)備練習(xí),我們現(xiàn)在要和volatile聯(lián)系起來(lái)了。我們將把C++的類(lèi)型和線程的語(yǔ)義作一個(gè)對(duì)比。

在一個(gè)臨界區(qū)以外,任意線程會(huì)在任何時(shí)間打斷別的線程;這是不受控制的,所以被多個(gè)線程訪問(wèn)的變量容易被改得面目全非。這和volatile的原意[1]是一致的——所以需要用volatile來(lái)防止編譯器無(wú)意地緩存這樣的變量。  

在由一個(gè)mutex限定的臨界區(qū)里,只有一個(gè)線程可以進(jìn)入。因此,在臨界區(qū)中執(zhí)行的代碼有和單線程程序有相同的語(yǔ)義。被控制的變量不會(huì)再被意外改變——你可以去掉volatile修飾。  

簡(jiǎn)而言之,線程間共享的數(shù)據(jù)在臨界區(qū)之外是volatile的,而在臨界區(qū)之內(nèi)則不是。  

你通過(guò)對(duì)一個(gè)mutex加鎖來(lái)進(jìn)入一個(gè)臨界區(qū),然后你用const_cast去掉某個(gè)類(lèi)型的volatile修飾,如果我們能成功地把這兩個(gè)操作放到一起,那么我們就在C++類(lèi)型系統(tǒng)和應(yīng)用程序的線程語(yǔ)義建立起聯(lián)系。這樣我們可以讓編譯器來(lái)幫我們檢測(cè)競(jìng)爭(zhēng)條件。

LockingPtr 
我們需要有一個(gè)工具來(lái)做mutex的獲取和const_cast兩個(gè)操作。讓我們來(lái)設(shè)計(jì)一個(gè)LockingPtr類(lèi),你需要用一個(gè)volatile的對(duì)象obj和一個(gè)mutex對(duì)象mtx來(lái)初始化它。在LockingPtr對(duì)象的生命期中,它會(huì)保證mtx處于被獲取狀態(tài),而且也提供對(duì)去掉volatile修飾的obj的訪問(wèn)。對(duì)obj的訪問(wèn)類(lèi)似于smart pointer,是通過(guò)operator->;和operator*來(lái)進(jìn)行的。const_cast是在LockingPtr內(nèi)部進(jìn)行。這個(gè)轉(zhuǎn)化在語(yǔ)義上是正確的,因?yàn)長(zhǎng)ockingPtr在其生存期中始終擁有mutex。  

首先,我們來(lái)定義和LockingPtr一起工作的Mutex類(lèi)的框架:  

class Mutex

{

public:

    void Acquire();

    void Release();

    ...    

};


為了使用LockingPtr,你需要用操作系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu)和底層函數(shù)來(lái)實(shí)現(xiàn)Mutex。  
LockingPtr是一個(gè)模板,用被控制變量的類(lèi)型作為模板參數(shù)。例如,如果你希望控制一個(gè)Widget,你就要這樣寫(xiě)LockingPtr <Widget>;。  

LockingPtr的定義很簡(jiǎn)單,它只是實(shí)現(xiàn)了一個(gè)單純的smart pointer。它關(guān)注的焦點(diǎn)只是在于把const_cast和臨界區(qū)操作放在一起。  

template <typename T>;

class LockingPtr 
{

public:

   // Constructors/destructors

   LockingPtr(volatile T& obj, Mutex& mtx)

       : pObj_(const_cast<T*>;(&obj)),

        pMtx_(&mtx)

   {    mtx.Lock();    }

   ~LockingPtr()

   {    pMtx_->;Unlock();    }

   // Pointer behavior

   T& operator*()

   {    return *pObj_;    }

   T* operator->;()

   {   return pObj_;   }

private:
   T* pObj_;

   Mutex* pMtx_;

   LockingPtr(const LockingPtr&);

   LockingPtr& operator=(const LockingPtr&);

};

盡管很簡(jiǎn)單,LockingPtr對(duì)于編寫(xiě)正確的多線程代碼非常有用。你應(yīng)該把線程間共享的對(duì)象聲明為volatile,但是永遠(yuǎn)不要對(duì)它們使用
const_cast——你應(yīng)該始終是用LockingPtr的自動(dòng)對(duì)象(automatic objects)。讓我們舉例來(lái)說(shuō)明。

比如說(shuō)你有兩個(gè)線程需要共享一個(gè)vector<char>;對(duì)象: 

class SyncBuf {

public:
    void Thread1();
    void Thread2();
private:
    typedef vector<char>; BufT;
    volatile BufT buffer_;
    Mutex mtx_; // controls access to buffer_
};

在一個(gè)線程的函數(shù)里,你只需要簡(jiǎn)單地使用一個(gè)LockingPtr<BufT>;對(duì)象來(lái)獲取對(duì)buffer_成員變量的受控訪問(wèn):

void SyncBuf::Thread1() {

    LockingPtr<BufT>; lpBuf(buffer_, mtx_);
    BufT::iterator i = lpBuf->;begin();
    for (; i != lpBuf->;end(); ++i) {
        ... use *i ...
    }
}

這樣的代碼很容易編寫(xiě),也很容易理解——每當(dāng)你需要使用buffer_時(shí),你必須創(chuàng)建一個(gè)LockingPtr<BufT>;來(lái)指向它。當(dāng)你這樣做了以后,你就
可以訪問(wèn)vector的全部接口。

這個(gè)方法的好處是,如果你犯了錯(cuò)誤,編譯器會(huì)指出它:  


void SyncBuf::Thread2() {
    // Error! Cannot access 'begin' for a volatile object
    BufT::iterator i = buffer_.begin();
    // Error! Cannot access 'end' for a volatile object
    for (; i != lpBuf->;end(); ++i) {
        ... use *i ...
    }
}

你不能訪問(wèn)buffer_的任何函數(shù),除非你進(jìn)行了const_cast或者用LockingPtr。這兩者的區(qū)別是LockingPtr提供了一個(gè)有規(guī)則的方法來(lái)對(duì)一個(gè)volatile變量進(jìn)行const_cast。  
LockingPtr有非常好的表達(dá)力。如果你只需要調(diào)用一個(gè)函數(shù),你可以創(chuàng)建一個(gè)無(wú)名的臨時(shí)LockingPtr對(duì)象,然后直接使用它:  

unsigned int SyncBuf::Size() {

    return LockingPtr<BufT>;(buffer_, mtx_)->;size();

}


回到原生類(lèi)型 
我們已經(jīng)看到了volatile對(duì)于保護(hù)對(duì)象免于不受控的訪問(wèn)是多么出色,并且看到了LockingPtr是怎么提供了一個(gè)簡(jiǎn)單有效的辦法來(lái)編寫(xiě)線程安全的代碼。現(xiàn)在讓我們回到原生類(lèi)型,volatile對(duì)它們的作用方式是不同的。 

讓我們來(lái)考慮一個(gè)多個(gè)線程共享一個(gè)int變量的例子。  


class Counter
{
public:
    ...
    void Increment() { ++ctr_; }
    void Decrement() { --ctr_; }
private:
    int ctr_;
};


如果Increment和Decrement是在不同的線程里被調(diào)用的,上面的代碼片斷里就有bug。首先,ctr_必須是volatile的。其次,即使是一個(gè)看上去是原子的操作,比如++ctr_,實(shí)際上也分為三個(gè)階段。內(nèi)存本身是沒(méi)有運(yùn)算功能的,當(dāng)對(duì)一個(gè)變量進(jìn)行增量操作時(shí),處理器會(huì):  
把變量讀入寄存器  
對(duì)寄存器里的值加1  
把結(jié)果寫(xiě)回內(nèi)存  
這個(gè)三步操作稱為RMW(Read-Modify-Write)。在一個(gè)RMW操作的Modify階段,大多數(shù)處理器都會(huì)釋放內(nèi)存總線,以使其他處理器能夠訪問(wèn)內(nèi)存。  
如果在這個(gè)時(shí)候另一個(gè)處理器對(duì)同一個(gè)變量也進(jìn)行RMW操作,我們就遇到了一個(gè)競(jìng)爭(zhēng)條件:第二次寫(xiě)入會(huì)覆蓋掉第一次的值。  

為了防止這樣的事發(fā)生,你又要用到LockingPtr:  

class Counter

{
public:
    ...
    void Increment() { ++*LockingPtr<int>;(ctr_, mtx_); }
    void Decrement() { --*LockingPtr<int>;(ctr_, mtx_); }
private:
    volatile int ctr_;
    Mutex mtx_;
};

現(xiàn)在這段代碼正確了,但是和SyncBuf相比,這段代碼的質(zhì)量要差一些。為什么?因?yàn)閷?duì)于Counter,編譯器不會(huì)在你錯(cuò)誤地直接訪問(wèn)ctr_(沒(méi)有對(duì)它加鎖)時(shí)產(chǎn)生警告。雖然ctr_是volatile的,但是編譯器還是可以編譯++ctr_,盡管產(chǎn)生的代碼絕對(duì)是不正確的。編譯器不再是你的盟友了,你只有自己留意競(jìng)爭(zhēng)條件。  
那么你該怎么做呢?很簡(jiǎn)單,你可以用一個(gè)高層的結(jié)構(gòu)來(lái)包裝原生類(lèi)型的數(shù)據(jù),然后對(duì)那個(gè)結(jié)構(gòu)使用volatile。這有點(diǎn)自相矛盾,直接用volatile修飾原生類(lèi)型是一個(gè)不好的用法,盡管這是volatile最初期望的用法!
到現(xiàn)在為止,我們討論了具有volatile數(shù)據(jù)成員的類(lèi);現(xiàn)在讓我們來(lái)考慮設(shè)計(jì)這樣的類(lèi),它會(huì)作為更大的對(duì)象的一部分并且在線程間共享。這里,volatile的成員函數(shù)可以幫很大的忙。  

在設(shè)計(jì)類(lèi)的時(shí)候,你只對(duì)那些線程安全的成員函數(shù)加volatile修飾。你必須假定外面的代碼會(huì)在任何地方任何時(shí)間調(diào)用volatile成員函數(shù)。不要忘記:volatile相當(dāng)于自由的多線程代碼,并且沒(méi)有臨界區(qū);非volatile相當(dāng)于單線程的環(huán)境或者在臨界區(qū)內(nèi)。  

比如說(shuō),你定義了一個(gè)Widget類(lèi),它用兩個(gè)方法實(shí)現(xiàn)了同一個(gè)操作——一個(gè)線程安全的方法和一個(gè)快速的不受保護(hù)的方法。

class Widget

{
public:
    void Operation() volatile;
    void Operation();
    ...
private:
    Mutex mtx_;
};


注意這里的重載(overloading)用法。現(xiàn)在Widget的用戶可以用一致的語(yǔ)法調(diào)用Operation,對(duì)于volatile對(duì)象可以得到線程安全性,對(duì)于普通對(duì)象可以得到速度。用戶必須注意把共享的Widget對(duì)象定義為volatile。  
在實(shí)現(xiàn)volatile成員函數(shù)時(shí),第一個(gè)操作通常是用LockingPtr對(duì)this進(jìn)行加鎖,然后其余工作可以交給非volatile的同名函數(shù)做: 

void Widget::Operation() volatile

{
    LockingPtr<Widget>; lpThis(*this, mtx_);
    lpThis->;Operation(); // invokes the non-volatile function
}

小結(jié) 
在編寫(xiě)對(duì)線程程序的時(shí)候,使用volatile將對(duì)你十分有益。你必須堅(jiān)持下面的規(guī)則:  

把所有共享對(duì)象聲明為volatile  
不要對(duì)原生類(lèi)型直接使用volatile  
定義共享類(lèi)時(shí),用volatile成員函數(shù)來(lái)表示它的線程安全性。  
如果你這么做了,而且用了簡(jiǎn)單的通用組件LockingPtr,你就可以寫(xiě)出線程安全的代碼,并且大大減少對(duì)競(jìng)爭(zhēng)條件的擔(dān)心,因?yàn)榫幾g器會(huì)替你操心,并且勤勤懇懇地為你指出哪里錯(cuò)了。  

在我參與的幾個(gè)項(xiàng)目中,使用volatile和LockingPtr產(chǎn)生了很大效果。代碼十分整潔,也容易理解。我記得遇到過(guò)一些死鎖的情況,但是相對(duì)于競(jìng)爭(zhēng)條件,我寧愿對(duì)付死鎖的情況,因?yàn)樗鼈冋{(diào)試起來(lái)容易多了。那些項(xiàng)目實(shí)際上根本沒(méi)有碰到過(guò)有關(guān)競(jìng)爭(zhēng)條件的問(wèn)題。  

致謝 
非常感謝James Kanze和Sorin Jianu提供了很有洞察力的意見(jiàn)。
致謝 
非常感謝James Kanze和Sorin Jianu提供了很有洞察力的意見(jiàn)。  

附:濫用volatile的本質(zhì)?[2] 
在上一期的專欄《Generic<Programming>;: volatile — Multithreaded Programmer's Best Friend》發(fā)表以后,我收到很多反饋意見(jiàn)。就像是注定的一樣,大部分稱贊都是私人信件,而抱怨都發(fā)到USENET新聞組comp.lang.c++.moderated和 comp.programming.threads里去了。隨后引起了很長(zhǎng)很激烈的討論,如果你對(duì)這個(gè)主題有興趣,你可以去看看這個(gè)討論,它的標(biāo)題是“volatile, was: memory visibility between threads.”。  

我知道我從這個(gè)討論中學(xué)到了很多東西。比如說(shuō),文章開(kāi)頭的Widget的例子不太切題。長(zhǎng)話短說(shuō),在很多系統(tǒng)(比如POSIX兼容的系統(tǒng))中,volatile修飾是不需要的,而在另一些系統(tǒng)中,即使加了volatile也沒(méi)有用,程序還是不正確。  

關(guān)于volatile correctness,最重要的一個(gè)問(wèn)題是它依賴于類(lèi)似POSIX的mutex,如果在多處理器系統(tǒng)上,光靠mutex就不夠了——你必須用memory barriers。  

另一個(gè)更哲理性的問(wèn)題是:嚴(yán)格來(lái)說(shuō)通過(guò)類(lèi)型轉(zhuǎn)換把變量的volatile屬性去掉是不合法的,即使volatile屬性是你自己為了volatile correctness而加上去的。正如Anthony Williams指出的,可以想象一個(gè)系統(tǒng)可能把volatile數(shù)據(jù)放在一個(gè)不同于非volatile數(shù)據(jù)的存儲(chǔ)區(qū)中,在這種情況下,進(jìn)行地址變換會(huì)有不確定的行為。 

另一個(gè)批評(píng)是volatile correctness雖然可以在一個(gè)較低層次上解決競(jìng)爭(zhēng)條件,但是不能正確的檢測(cè)出高層的、邏輯的競(jìng)爭(zhēng)條件。例如,你有一個(gè)mt_vector模版類(lèi),用來(lái)模擬std::vector,成員函數(shù)經(jīng)過(guò)正確的線程同步修正。考慮這段代碼:  

volatile mt_vector<int>; vec; 
 
if (!vec.empty()) { 
    vec.pop_back(); 
} 

這段代碼的目的是刪除vector里的最后一個(gè)元素,如果它存在的話。在單線程環(huán)境里,他工作地很好。然而如果你把它用在多線程程序里,這段代碼還是有可能拋出異常,盡管empty和pop_back都有正確的線程同步行為。雖然底層的數(shù)據(jù)(vec)的一致性有保證,但是高層操作的結(jié)果還是不確定的。  
無(wú)論如何,經(jīng)過(guò)辯論之后,我還是保持我的建議,在有類(lèi)POSIX的mutex的系統(tǒng)上,volatile correctness還是檢測(cè)競(jìng)爭(zhēng)條件的一個(gè)有價(jià)值的工具。但是如果你在一個(gè)支持內(nèi)存訪問(wèn)重新排序的多處理器系統(tǒng)上,你首先需要仔細(xì)閱讀你的編譯器的文檔。你必須知己知彼。
最后,Kenneth Chiu提到了一篇非常有趣的文章http://theory.stanford.edu/~freunds/race.ps,猜猜題目是什么?“Type-Based Race Detection for Java”。這篇文章講了怎么對(duì)Java的類(lèi)型系統(tǒng)作一點(diǎn)小小的補(bǔ)充,從而讓編譯器和程序員一起在編譯時(shí)檢測(cè)競(jìng)爭(zhēng)條件。  

Eppur si muove.[3] 
譯注 
[1] Volatile原意為易變的,反復(fù)無(wú)常的。  

[2] 這是Andrei在他的下一篇Generic<Programming>;里對(duì)本文作的補(bǔ)充說(shuō)明。  

[3] 這是伽利略在被迫放棄他一直信仰的哥白尼的地動(dòng)說(shuō)時(shí)所說(shuō)過(guò)的一句辯解的話,意思是“它(地球)畢竟仍在運(yùn)動(dòng)”。

posted on 2011-04-05 17:41 沛沛 閱讀(460) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): C++
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲一级高清| 国产精品日韩高清| 亚洲系列中文字幕| 噜噜噜噜噜久久久久久91| 亚洲久久在线| 国产视频一区在线观看一区免费| 午夜一区在线| 亚洲精选91| 久久免费99精品久久久久久| 在线午夜精品自拍| 在线欧美一区| 国产精品资源| 欧美精品aa| 久久久久久999| 一本色道精品久久一区二区三区| 久久亚洲欧美| 新狼窝色av性久久久久久| 亚洲精品你懂的| 在线免费观看欧美| 国产美女一区二区| 欧美日韩一区视频| 欧美va日韩va| 久久综合伊人| 久久久久国产一区二区三区| 亚洲一区二区三区四区中文| 亚洲精品久久嫩草网站秘色| 久热精品在线| 久久成人羞羞网站| 在线视频欧美日韩精品| 亚洲国产高清一区| 激情五月婷婷综合| 国产欧美日韩中文字幕在线| 欧美日一区二区三区在线观看国产免| 欧美一级专区| 亚洲视频免费在线| 99精品国产福利在线观看免费| 欧美激情黄色片| 蜜臀av在线播放一区二区三区| 欧美一级夜夜爽| 亚洲综合精品自拍| 亚洲视频高清| 亚洲人成在线播放网站岛国| 尤妮丝一区二区裸体视频| 国产视频久久| 国产精品一区免费观看| 国产精品色婷婷久久58| 国产一区二区三区在线播放免费观看| 国产在线视频不卡二| 精品福利免费观看| 亚洲人成网站777色婷婷| 亚洲伦理在线观看| 亚洲视频欧美视频| 欧美一区二区在线看| 久久久在线视频| 欧美国产另类| 99pao成人国产永久免费视频| 亚洲少妇最新在线视频| 欧美一区二区三区免费大片| 久久精品女人的天堂av| 欧美国产第二页| 国产精品久久久久一区| 韩国成人福利片在线播放| 亚洲日本久久| 午夜综合激情| 欧美国产日韩xxxxx| 妖精视频成人观看www| 欧美在线免费| 欧美精品在线一区| 国产毛片一区二区| 亚洲激情图片小说视频| 亚洲欧美成人网| 欧美sm重口味系列视频在线观看| 亚洲另类自拍| 欧美在线视频网站| 欧美日本在线观看| 国产视频自拍一区| 99精品热视频只有精品10| 欧美永久精品| 亚洲精品永久免费| 久久精品国产一区二区电影 | 久久精品国产精品| 欧美mv日韩mv亚洲| 国产美女精品视频| 亚洲乱码久久| 久久午夜国产精品| 一区二区三区www| 久久亚洲午夜电影| 亚洲欧美日韩中文视频| 免费av成人在线| …久久精品99久久香蕉国产 | 亚洲大胆视频| 亚洲天堂偷拍| 欧美成人精品h版在线观看| 亚洲天堂网在线观看| 美女性感视频久久久| 国产视频在线一区二区| 这里只有精品丝袜| 国产精品久久久91| 在线精品国产欧美| 欧美一区日韩一区| 夜夜爽www精品| 免费在线视频一区| 激情六月综合| 久久电影一区| 亚洲图片欧美午夜| 欧美日韩不卡视频| 亚洲日本欧美| 欧美凹凸一区二区三区视频| 欧美在现视频| 国产欧美日韩专区发布| 亚洲一区二三| 欧美激情偷拍| 亚洲视频观看| 亚洲欧洲在线看| 亚洲精品日韩一| 午夜精品av| 欧美va亚洲va国产综合| 国产精品久久一区二区三区| 精品成人在线| 亚洲欧美日韩成人高清在线一区| 久久久精品国产99久久精品芒果| 亚洲第一狼人社区| 亚洲黄色视屏| 久久精品亚洲国产奇米99| 久久亚洲欧洲| 一色屋精品亚洲香蕉网站| 久久国产加勒比精品无码| 亚洲一区二区成人| 欧美午夜精品久久久| 日韩一级欧洲| 亚洲精品人人| 欧美日韩一区综合| 国产精品99久久久久久人| 99精品视频免费| 久久精品一区二区国产| 国产综合自拍| 免费成人黄色| 亚洲精品一区二区三区蜜桃久| 亚洲第一精品电影| 欧美国内亚洲| 亚洲一区精品在线| 亚洲天堂第二页| 国产欧美一级| 久久五月激情| 欧美电影资源| 亚洲一区二区三区在线观看视频 | 亚洲国产成人tv| 欧美精品一区二区蜜臀亚洲| 一区二区三区欧美亚洲| 9i看片成人免费高清| 国产精品视频午夜| 久久午夜电影网| 欧美大片在线观看一区| 在线综合亚洲欧美在线视频| 亚洲愉拍自拍另类高清精品| 国内精品**久久毛片app| 欧美福利电影网| 欧美三级日本三级少妇99| 欧美一区二区三区四区夜夜大片 | 蜜桃精品一区二区三区| 欧美大片在线看免费观看| 亚洲图片在线观看| 欧美一区亚洲| 日韩视频一区| 亚洲欧美日韩成人| 亚洲激情小视频| 一区二区精品国产| 伊人久久av导航| 日韩一区二区免费高清| 国产亚洲一二三区| 亚洲欧洲精品一区二区| 国产欧美日韩亚洲| 亚洲电影免费观看高清| 欧美99久久| 久久精品水蜜桃av综合天堂| 久久综合精品一区| 9久草视频在线视频精品| 亚洲欧美日韩中文视频| 亚洲人体影院| 午夜精彩视频在线观看不卡 | 亚洲精品一区二区三区婷婷月| 国产日韩av在线播放| 亚洲国产综合91精品麻豆| 国产精品爽黄69| 亚洲黄一区二区三区| 国产亚洲一区在线播放| 日韩一级片网址| 亚洲二区精品| 小黄鸭精品密入口导航| 亚洲神马久久| 免费亚洲电影在线| 久久久综合免费视频| 国产精品国产三级国产aⅴ浪潮| 欧美成人国产一区二区| 国产日韩在线看片| 99精品免费网| 亚洲美女在线国产| 美女爽到呻吟久久久久| 久久久噜噜噜久久| 国产精品免费观看视频|