2014-01-22 28 views
0

我可以把關鍵部分衆多如果,否則條件,如我在下面顯示?關鍵部分,如果,否則在多線程應用程序

例如1

somefunction() 
    { 
      EnterCriticalSection(&(g_variable)); 

      if (...) 
      { 
       if (...) 
       { 
       ...  

       } 
       else 
       { 
        ... 
        if (...) 
        {...} 
       else if (...) 
        {...}  

      LeaveCriticalSection(&(g_variable)); 

       } 
      } 
      else 
      { 
        ...  
      } 


    } 

或嵌套他們是這樣的:

例如2

EnterCriticalSection(&g_List); 
EnterCriticalSection(&g_Variable); 
... 
LeaveCriticalSection(&g_List); 
LeaveCriticalSection(&g_Variable); 

預先感謝幫助。

+1

是的,你可以把你的代碼中提到的關鍵部分。例如2,如果其他線程使用相同的關鍵部分,請確保您保持相同的代碼序列,否則將導致死鎖情況。 – Sumeet

+1

在C++中,您應該__always__將其包裝到一個類中,該類將進入構建的臨界區並使其銷燬。如果您需要在對象的生命週期中多次離開/重新輸入,請添加「Enter」和「Leave」功能。 –

回答

1

你的可以做什麼和應該做什麼有什麼區別。

可以做你在你的問題中顯示。至少在我看來,應該是所做的(因爲您使用的是C++)使用RAII包裝來自動獲取您的LeaveCriticalSection調用以匹配您的EnterCriticalSection調用。

class crit_sect { 
    CRITICAL_SECTION cs; 

    void lock() { EnterCriticalSection(&cs); } 
    void unlock() { LeaveCriticalSection(&cs); } 
    friend class lock; 

    crit_sect(crit_sect const &); /* = delete; */ 
    crit_sect &operator=(crit_sect const &other); /* = delete; */ 
public: 
    crit_sect() { InitializeCriticalSection(&cs); } 
    ~crit_sect() { DeleteCriticalSection(&cs); } 
}; 

class lock { 
    crit_sect &cs; 
public: 
    lock(crit_sect &c) : cs(c) { cs.lock(); } 
    ~lock() { cs.unlock(); } 
}; 

使用這些,你必須是這樣的:

if (whatever) { 
    lock list_lock(g_List); 
    lock var_lock(g_Variable); 

// ... 

} 

...並在執行離開,其中兩把鎖被定義範圍,析構函數將執行,自動解鎖關鍵部分。這很方便,方便;如果使用異常,它變得更加重要,因爲這意味着如果通過異常而不是通過正常執行退出範圍,關鍵部分仍將被解鎖。

+0

如果我在上面的例子nr 2中使用你的解決方案,它會是無死鎖的嗎? – maciekm

+1

@maciekm:如果這就是你的意思,它不會在代碼中引入任何死鎖。你可以引入死鎖,這取決於你做了什麼。如果/當您嘗試同時獲取兩個或更多鎖時,死鎖主要發生。在這種情況下,你想確保一切嘗試以相同的順序獲取它們。 'lock locker1(a); lock locker2(b);'無處不在。添加一個鎖locker1(b);鎖locker2(a);'在一個地方,你有潛在的僵局。 –

2

在示例1中,這是壞習慣。更好地進行威脅臨界區的代碼塊

EnterCriticalSection(&g_Variable); 
{ 
    .... 
} 
LeaveCriticalSection(&g_Variable); 

更妙的是,是使用範圍CS類:

class CScopeCS{ 
    CRITICAL_SECTION& m_cs; 
public: 
    CScopeCS(CRITICAL_SECTION& cs):m_cs(cs){ 
    EnterCriticalSection(cs); 
    } 
    ~CScopeCS(){ 
    LeaveCriticalSection(m_cs); 
    } 
} 

,當從關鍵部分退出塊,它會自動調用析構函數。

{ 
    CScopeCS scopeLock(g_cs); 
    .... 
}//end of critical section 

在例2中,它會像你寫的,但你最好把最後一個第一:

EnterCriticalSection(&g_List); 
EnterCriticalSection(&g_Variable); 
... 
LeaveCriticalSection(&g_Variable); 
LeaveCriticalSection(&g_List); 

但你必須在同一順序的兩個關鍵部分在你的代碼防止死鎖。 (即第一個g_List然後是g_Variable),如果你已經進入了g_Variable並且想要進入g_List,你必須離開g_Variable並按順序進行。

1

簡答:是的,你可以。但是,使用Enter/LeaveCriticalSection對來犯錯誤很容易。你自己的代碼顯示,在頂部的關鍵部分之後,有一些代碼路徑,關鍵部分沒有發佈LeaveCriticalSection。其中一個路徑是第一個if語句的else塊,但另一個更隱蔽的路徑是當它們之間的某些代碼拋出異常時。

您將問題標記爲C++;如果C++ 11可用,那麼有一個很好的選擇:來自標準頭文件的類,例如recursive_mutex和lock_guard。您的代碼如下所示:

recursive_mutex g_variable; 

someFunction() 
{ 
    lock_guard<recursive_mutex> lock(g_variable); 

    if (...) 
     ... 
    else 
     ... 
} 

現在您可以確保在離開某個函數()後釋放互斥鎖。而且你必須輸入較少,而且你的代碼也是可移植的。