簡體   English   中英

吸氣劑的c ++ criticalsection

[英]c++ criticalsection for getter

我有一個簡單的類,有一個私有成員,可以通過多線程環境中的get()和set()訪問(多讀者/多作者)。 如何鎖定Get(),因為它只有一個return語句?

class MyValue
{
  private:
    System::CriticalSection lock;
    int val { 0 };

  public:
    int SetValue(int arg)
    {
        lock.Enter();
        val = arg;
        lock.Leave();
    }

    int GetValue()
    {
        lock.Enter();
        return val;
        //Where should I do lock.Leave()?
    }   
}

不要鎖定任何東西。 在您的示例中,如果您使您的成員成為std::atomic整數就足夠了。

你這里不需要任何其他東西。 事實上,由於英特爾架構(強大的內存排序模型),這個std::atomic甚至不會引起任何性能問題。

我不是多線程專家,但我認為以下應該可行。

int GetValue()
{
    lock.Enter();
    int ret = val;
    lock.Leave();
    return ret;
}   

這是來自hauron的答案的同步對象的演示 - 我想表明,對象構造和破壞開銷根本不存在與光學構建。

在下面的代碼中,CCsGrabber是一個類似RAII的類,在構造時進入臨界區(由CCritical對象包裝),然后在銷毀時離開它:

class CCsGrabber {
    class CCritical& m_Cs;
    CCsGrabber();
public:
    CCsGrabber(CCritical& cs);
    ~CCsGrabber();
};

class CCritical {
    CRITICAL_SECTION cs;
public:
    CCritical()       { 
        InitializeCriticalSection(&cs); 
    }
    ~CCritical()      { DeleteCriticalSection(&cs); }
    void Enter()      { EnterCriticalSection(&cs); }
    void Leave()      { LeaveCriticalSection(&cs); }
    void Lock()       { Enter(); }
    void Unlock()     { Leave(); }
};

inline CCsGrabber::CCsGrabber(CCritical& cs)  : m_Cs(cs)   { m_Cs.Enter(); }
inline CCsGrabber::CCsGrabber(CCritical *pcs) : m_Cs(*pcs) { m_Cs.Enter(); }
inline CCsGrabber::~CCsGrabber()                           { m_Cs.Leave(); }

現在,創建一個全局CCritical對象(cs),它在SerialFunc() ,以及一個本地CCsGrabber實例(csg)來處理鎖定和解鎖:

CCritical cs;
DWORD last_tick = 0;

void SerialFunc() {
    CCsGrabber csg(cs);
    last_tick = GetTickCount();
}

int main() {
    SerialFunc();
    std::cout << last_tick << std::endl;
}

以下是main()與優化的32位構建的解集。 (我為整個事情的粘貼道歉 - 我想表明我沒有隱藏任何東西:

int main() {
00401C80  push        ebp  
00401C81  mov         ebp,esp  
00401C83  and         esp,0FFFFFFF8h  
00401C86  push        0FFFFFFFFh  
00401C88  push        41B038h  
00401C8D  mov         eax,dword ptr fs:[00000000h]  
00401C93  push        eax  
00401C94  mov         dword ptr fs:[0],esp  
00401C9B  sub         esp,0Ch  
00401C9E  push        esi  
00401C9F  push        edi  
    SerialFunc();
00401CA0  push        427B78h                          ; pointer to CS object
00401CA5  call        dword ptr ds:[41C00Ch]           ; _RtlEnterCriticalSection@4:
00401CAB  call        dword ptr ds:[41C000h]           ; _GetTickCountStub@0:
00401CB1  push        427B78h                          ; pointer to CS object
00401CB6  mov         dword ptr ds:[00427B74h],eax     ; return value => last_tick
00401CBB  call        dword ptr ds:[41C008h]           ; _RtlLeaveCriticalSection@4: 
    std::cout << last_tick << std::endl;
00401CC1  push        ecx  
00401CC2  call        std::basic_ostream<char,std::char_traits<char> >::operator<< (0401D90h)  
00401CC7  mov         esi,eax  
00401CC9  lea         eax,[esp+0Ch]  
00401CCD  push        eax  
00401CCE  mov         ecx,dword ptr [esi]  
00401CD0  mov         ecx,dword ptr [ecx+4]  
00401CD3  add         ecx,esi  
00401CD5  call        std::ios_base::getloc (0401BD0h)  
00401CDA  push        eax  
00401CDB  mov         dword ptr [esp+20h],0  
00401CE3  call        std::use_facet<std::ctype<char> > (0403E40h)  
00401CE8  mov         dword ptr [esp+20h],0FFFFFFFFh  
00401CF0  add         esp,4  
00401CF3  mov         ecx,dword ptr [esp+0Ch]  
00401CF7  mov         edi,eax  
00401CF9  test        ecx,ecx  
00401CFB  je          main+8Eh (0401D0Eh)  
00401CFD  mov         edx,dword ptr [ecx]  
00401CFF  call        dword ptr [edx+8]  
00401D02  test        eax,eax  
00401D04  je          main+8Eh (0401D0Eh)  
00401D06  mov         edx,dword ptr [eax]  
00401D08  mov         ecx,eax  
00401D0A  push        1  
00401D0C  call        dword ptr [edx]  
00401D0E  mov         eax,dword ptr [edi]  
00401D10  mov         ecx,edi  
00401D12  push        0Ah  
00401D14  mov         eax,dword ptr [eax+20h]  
00401D17  call        eax  
00401D19  movzx       eax,al  
00401D1C  mov         ecx,esi  
00401D1E  push        eax  
00401D1F  call        std::basic_ostream<char,std::char_traits<char> >::put (0404220h)  
00401D24  mov         ecx,esi  
00401D26  call        std::basic_ostream<char,std::char_traits<char> >::flush (0402EB0h)  
}
00401D2B  mov         ecx,dword ptr [esp+14h]  
00401D2F  xor         eax,eax  
00401D31  pop         edi  
00401D32  mov         dword ptr fs:[0],ecx  
00401D39  pop         esi  
00401D3A  mov         esp,ebp  
00401D3C  pop         ebp  
00401D3D  ret  

所以我們可以看到SerialFunc()直接內聯到main,在開頭的序言之后和cout代碼之前 - 並且無處可尋找任何超級對象創建,內存分配或任何東西 - 它看起來像最小量進入臨界區所需的匯編代碼,獲取變量中的滴答計數,然后離開臨界區。

然后我將SerialFunc()更改為:

void SerialFunc() {
    cs.Enter();
    last_tick = GetTickCount();
    cs.Leave();
}

使用顯式放置的cs.Enter()cs.Leave() ,只是為了與RAII版本進行比較。 生成的代碼結果相同:

    int main() {
00401C80  push        ebp  
00401C81  mov         ebp,esp  
00401C83  and         esp,0FFFFFFF8h  
00401C86  push        0FFFFFFFFh  
00401C88  push        41B038h  
00401C8D  mov         eax,dword ptr fs:[00000000h]  
00401C93  push        eax  
00401C94  mov         dword ptr fs:[0],esp  
00401C9B  sub         esp,0Ch  
00401C9E  push        esi  
00401C9F  push        edi  
        SerialFunc();
00401CA0  push        427B78h  
00401CA5  call        dword ptr ds:[41C00Ch]  
00401CAB  call        dword ptr ds:[41C000h]  
00401CB1  push        427B78h  
00401CB6  mov         dword ptr ds:[00427B74h],eax  
00401CBB  call        dword ptr ds:[41C008h]  
        std::cout << last_tick << std::endl;
00401CC1  push        ecx  
00401CC2  call        std::basic_ostream<char,std::char_traits<char> >::operator<< (0401D90h)  
                         ...

在我看來,SergeyA的答案最適合給定的情況 - 從32位變量同步讀取和寫入的關鍵部分過多。 但是,如果出現需要關鍵部分或互斥鎖的東西,使用類似RAII的對象來簡化代碼可能不會產生大量(甚至任何)對象創建開銷。

(我使用Visual C ++ 2013編譯上面的代碼)

考慮在ctor中使用類包裝器鎖定,並在dtor中解鎖。 請參閱標准實施: http//en.cppreference.com/w/cpp/thread/unique_lock

這樣,在代碼中拋出復雜代碼或異常的情況下,您無需記住解鎖,從而改變正常執行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM