2011-05-19 198 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