2011-05-19 194 views
3

我已經被挖掘出來支持一些遺留代碼,並且我看到一些讓我在困惑中撓頭的東西。在代碼的某些部分,我看到類實例使用CMutex實例來同步方法執行。例如CMutex :: Lock與CSingleLock :: Lock

class CClassA : public CObject 
{ 
public: 
    void DoSomething(); 

private: 
    CMutex m_mutex; 
} 

void CClassA::DoSomething() 
{ 
    m_mutex.Lock(); 

    //...logic... 

    m_mutex.Unlock(); 
} 

其他地方在同一個項目中,我發現代碼使用CSingleLock

class CClassB : public CObject 
{ 
public: 
    void DoSomething(); 

private: 
    CCriticalSection m_crit; 
} 

void CClassB::DoSomething() 
{ 
    CSingleLock lock(&m_crit); 
    lock.Lock(); 

    //...logic... 

    lock.Unlock(); 
} 

審查MSDN documentation for synchronization後,它會出現CClassB正在實施的建議方法,但它不是清楚了CClassA所使用的實施過程中的危險。據我所知,這兩種方法之間的唯一區別是CSingleLock具有RAII的優點,所以當執行退出範圍時鎖會自動釋放。這兩種實施是否還有其他優點/缺點?

+0

要添加一些上下文,我的一個擔心是如果使用CSingleLock :: Lock具有細微差別的行爲。例如,在同一個線程可能能夠多次調用CMutex :: Lock(因爲它已經擁有該鎖)的情況下,在CSingleLock的同一個實例上對CSingleLock :: Lock的調用將被阻塞。我也擔心我可能遇到一個情況,即CSingleLock正在管理一個CCriticalSection,但該CCriticalSection具有直接調用的Unlock方法。 – JadeMason 2011-05-19 18:41:38

回答

1

通常互斥鎖可以用來通過一個已命名的互斥體控制跨進程的線程訪問,而關鍵部分僅用於在同一進程空間中同步線程訪問。

這兩個類沒有包裝它們都不會真正獲得RAII的好處,因爲在這種情況下,您永遠不需要明確地調用鎖定或解鎖。舉個例子,使用升壓互斥鎖僞代碼這一點點......

void DoSomething() 
{ 
    // construction acquires lock on mutex 
    boost::scoped_lock lock(&aBoostMutex); 

    // ... 

} // end scope - object is destroyed and lock is released 

現在我要說,你應該避免CMutexCCritalSectionCSemaphoreCEvent因爲實現被打破有些或非常最不如其他可用的庫如boost。例如:

  • 確定來自廢棄互斥體的超時是不可能的,因爲實施僅檢查返回值而不是原因。
  • 沒有使用CSingleLock這樣遞歸的可重入鎖將導致問題。
  • 不能有一個名爲事件之間處理

取決於你與你的任務是什麼可能需要從MFC包裝移開在Windows API的機會,要麼實現自己的原子鎖或使用類似boost或C++ 0x功能,如std::mutex這不僅是更好的實現,而且提供跨平臺支持。

+1

不幸的是,我被MFC困住了。我的問題不是關於CMutex和CCriticalSection之間的區別,更多關於CSyncObject :: Lock和CSingleLock :: Lock之間的區別。在做了一些更多的研究之後,看起來CSingleLock的行爲類似於上面顯示的boost :: scoped_lock(在析構函數上調用Unlock)。我沒有意識到CSingleLock阻止遞歸,我認爲堆棧中的每個新實例都將獨立管理。 – JadeMason 2011-05-23 20:21:54

+0

據我所知,'CSyncObject'在封面下調用Windows api'WaitForSingleObject',不能直接使用。它是'CMutex'派生出來的基類接口,所以當你在你的實例上執行'CMutex :: Lock();'時會使用它。 'CSingleLock'是你的'CCriticalSection'操縱器,它是具體的,可以用作一些封裝的範圍鎖。如前所述,雖然這些對象存在一些設計問題,所以應避免使用http://www.flounder.com/avoid_mfc_syncrhonization.htm – AJG85 2011-05-23 20:29:31

+0

對於將來的讀者,CSingleLock有一個[構造函數](https://msdn.microsoft.com/zh-cn/library/default.aspx)。 com/en-us/library/fw63hszf.aspx)會導致它在構建時被鎖定的參數。 OP的例子並沒有使用它,這是使用CSingleLock的最大原因。 – JPhi1618 2016-02-16 21:53:41

1

關鍵部分僅對單個進程內的線程可見/可用。一個互斥體可以在多個進程中可見(通常通過創建一個已命名的互斥體)。你上面顯示的內容不足以說明這是他們爲什麼都有,但這是一種可能性。

+0

從我所知道的情況來看,這段代碼永遠不需要跨進程邊界的同步。這使我相信CCLassA中的CMutex可以用一個CCriticalSection代替。 – JadeMason 2011-05-19 18:31:34