我被挖掘支持一些遗留代码,我看到一些让我困惑地挠头的事情。 在某些代码部分中,我看到类实例使用 CMutex 实例来同步方法执行。 例如
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 文档以进行同步后,CClassB 似乎正在实现建议的方法,但我不清楚 CClassA 使用的实现中存在什么危险。 据我所知,这两种方法之间的唯一区别是CSingleLock具有RAII的优点,因此当执行退出范围时,锁会自动释放。 这两种实现还有其他优点/缺点吗?
互斥锁可用于通过命名互斥锁控制跨进程的线程访问,而关键部分仅用于在同一进程空间中同步线程访问。
如果不包装它们,这些类都不会真正获得 RAII 的好处,因为在这种情况下,您永远不需要显式调用锁定或解锁。 以使用boost互斥锁的这点伪代码为例......
void DoSomething()
{
// construction acquires lock on mutex
boost::scoped_lock lock(&aBoostMutex);
// ...
} // end scope - object is destroyed and lock is released
现在我认为你应该避免CMutex
、CCritalSection
、CSemaphore
和CEvent
,因为实现有些损坏,或者至少不如其他可用的库,如 boost。 例如:
- 确定放弃互斥锁的超时是不可能的,因为实现只检查返回值而不是原因。
- 没有使用
CSingleLock
的重入锁,因此递归会导致问题。 - 无法在进程之间具有命名事件
根据你的任务,你可能有机会摆脱Windows API上的MFC包装器,实现你自己的原子锁,或者使用像boost或C++0x功能,如std::mutex
,这不仅是更好的实现,而且提供跨平台支持。
关键部分仅对单个进程内的线程可见/可用。互斥锁可以在多个进程中可见(通常通过创建命名互斥锁)。你上面显示的还不足以说明这是否是他们两者兼而有之的原因,但这是一种可能性。