在多线程编程成中经常需要进行数据同步等操作,在临界区等对象使用时容易出现忘记退出临界区操作或中间执行的代码发生异常导致退出临界区代码未被正常执行,这个时候就很容易出现死锁现象了,那么我们这么解决上述问题呢?
这个问题解决的办法其实很简单,采用临时对象的方式去解决,也就是写一个自动锁的类,这个类用于接收一个临界区指针或引用,在构造时自动进入临界区,析构时自动退出临界区,那么我们也用关心是否遗漏退出临界区的代码或者被异常给终止了退出临界区的代码。
以下为实现:
SafetyAutoLock.h
/** *@class SafetyAutoLock *@brief 安全自动锁类,防止手动忘记释放临界区或异常导致临界区未释放 *@author Flyound *@note *必须采用栈方式使用,不允许跨代码段({...}/void func(){}) */ class SafetyAutoLock { public: SafetyAutoLock(CRITICAL_SECTION * pCSLock); SafetyAutoLock(CRITICAL_SECTION * pCSLock, const char * szFile, const char * szFunc, long lLine); virtual ~SafetyAutoLock(void); public: /**@brief 手动锁*/ void Lock(); /**@brief 手动释放锁,无需等待析构*/ void UnLock(); /**@brief 重新设置临界区*/ void Reset(CRITICAL_SECTION * pCSLock); /**@brief 重新设置临界区*/ void Reset(CRITICAL_SECTION * pCSLock, const char * szFile, const char * szFunc, long lLine); /**@brief 判断该锁是否有效(临界区指针是否正常)*/ bool IsValid(); private: int m_nLockCount; DWORD m_dwCallStackID; CRITICAL_SECTION * m_pCSLock; };
SafetyAutoLock.cpp
SafetyAutoLock::SafetyAutoLock(CRITICAL_SECTION * pCSLock)
{
m_nLockCount = 0;
m_pCSLock = pCSLock;
Lock();
}
SafetyAutoLock::SafetyAutoLock(CRITICAL_SECTION * pCSLock, const char * szFile, const char * szFunc, long lLine)
{
m_nLockCount = 0;
m_pCSLock = pCSLock;
Lock();
}
SafetyAutoLock::~SafetyAutoLock(void)
{
Reset(NULL);
}
void SafetyAutoLock::Lock()
{
if (m_pCSLock)
{
m_nLockCount++;
EnterCriticalSection(m_pCSLock);
}
}
void SafetyAutoLock::UnLock()
{
if (m_pCSLock && (--m_nLockCount) == 0)
{
LeaveCriticalSection(m_pCSLock);
}
}
void SafetyAutoLock::Reset(CRITICAL_SECTION * pCSLock)
{
while(m_nLockCount > 0)
{
UnLock();
}
m_nLockCount = 0;
m_pCSLock = pCSLock;
Lock();
}
void SafetyAutoLock::Reset(CRITICAL_SECTION * pCSLock, const char * szFile, const char * szFunc, long lLine)
{
if (pCSLock)
{
Reset(pCSLock);
}
}
bool SafetyAutoLock::IsValid()
{
return m_pCSLock != NULL;
}
上述代码能帮助我们规避因为粗心引起的死锁问题,那么下一篇将讲解如果监控死锁的发生,并能得知死锁发生的原因,快速定位死锁的代码并解决它。