死锁

简介: 死锁

死锁的最常见情况


相互等待。 


业务说明


对于简单的业务,可以规定一次只能锁定一个单元,但对于复杂业务,这种方法不可行。比如:金银互换,1金换10银。分4步:1,判断金币足够。 2,判断银币没到上限 3,金币减少。 4,银币增加。假定只有一金币,线程一执行步骤一,发现金币足够,碰巧线程被挂起; 线程二执行执行步骤一,发现金币足够。于是金币变成了-1。为了避免这种情况,必须同时锁金银。函数一,先锁金,再锁银;函数二,先锁银,再锁金。可能出现如下情况:线程一,锁了金,想锁银;线程二,锁了银,想锁金。


测试代码


namespace TEST1
{
class CTestDeadLock
{
public:
static UINT Test1(LPVOID)
{// 模拟一金币换10银币
s_lock1.Lock();
Sleep(1);
s_lock2.Lock();
if ( ( s_iJin > 0) && (s_iYin < 1000 ) )
{
s_iJin--;
s_iYin += 10;
}
s_lock1.UnLock();
s_lock2.UnLock();
return 0;
}
static UINT Test2(LPVOID)
{
s_lock2.Lock();
Sleep(1);
s_lock1.Lock();
if ((s_iYin > 10) && (s_iJin < 1000))
{
s_iYin-= 10;
s_iJin++;
}
s_lock2.UnLock();
s_lock1.UnLock();
return 0;
}
protected:
static SNMFC::CriticalReadWriteLock s_lock1;
static SNMFC::CriticalReadWriteLock s_lock2;
static int s_iJin;
static int s_iYin;
};
SNMFC::CriticalReadWriteLock CTestDeadLock::s_lock1;
SNMFC::CriticalReadWriteLock CTestDeadLock::s_lock2;
int CTestDeadLock::s_iJin =0;
int CTestDeadLock::s_iYin = 0;
}
void CSNMFCDlg::OnBnClickedButton22()
{
AfxBeginThread(TEST1::CTestDeadLock::Test1, NULL);
TEST1::CTestDeadLock::Test2(NULL);
}


解决方法


上面的Sleep(1)是为了模拟碰巧被挂起。解决死锁的方法:按特定的顺序锁。如果要锁的单元多,调用者根本无法知道,先锁那个。


锁管理类


先设置标志,Lock的时候自动按顺序锁。


namespace TEST2
{
//每个线程都自动分配锁
class IRWLocks : public SN::IReadWriteLock
{
public:
virtual bool HasLock() = 0;
virtual bool HasLockRead() = 0;
};
//为每个线程都生产一把锁
class CCriticalRWLocks : public IRWLocks
{
protected:
class CLockInfo : public SNMFC::CriticalReadWriteLock
{
public:
CLockInfo()
{
m_iLockNum = 0;
m_iLockReadNum = 0;
}
virtual void Lock() override
{
SNMFC::CriticalReadWriteLock::Lock();
m_iLockNum++;
}
virtual void UnLock() override
{
m_iLockNum--;
SNMFC::CriticalReadWriteLock::UnLock();
}
virtual void LockRead() override
{
m_iLockReadNum++;
SNMFC::CriticalReadWriteLock::LockRead();
}
virtual void UnLockRead() override
{
m_iLockReadNum--;
SNMFC::CriticalReadWriteLock::UnLockRead();
}
bool HasLock()const
{
return m_iLockNum > 0;
}
bool HasLockRead()const
{
return m_iLockReadNum > 0;
}
protected:
int m_iLockNum ;
int m_iLockReadNum ;
};
public:
CCriticalRWLocks()
{
Init();
}
virtual void Lock() override
{
GetLockByCurrentThreadID()->Lock();
}
virtual void UnLock() override
{
GetLockByCurrentThreadID()->UnLock();
}
virtual void LockRead() override
{
GetLockByCurrentThreadID()->LockRead();
}
virtual void UnLockRead() override
{
GetLockByCurrentThreadID()->UnLockRead();
}
bool HasLock() override
{
return GetLockByCurrentThreadID()->HasLock();
}
bool HasLockRead() override
{
return GetLockByCurrentThreadID()->HasLockRead();
}
protected:
CLockInfo* GetLockByCurrentThreadID()
{
SN::CLockHlp lock(m_lock);
DWORD dThreadID = ::GetCurrentThreadId();
if (m_mLocks.end() == m_mLocks.find(dThreadID))
{
m_mLocks[dThreadID] = new CLockInfo();
}
return m_mLocks[dThreadID] ;
}
virtual void Init()
{
m_lock.Init();
}
std::map<int, CLockInfo*> m_mLocks;
SNMFC::CCriticalSection m_lock;
};
template<class DATA>
class CLockUnit
{
public:
DATA* GetData()
{
if (!m_locks.HasLock())
{
return NULL;
}
return &m_data;
}
const DATA* GetConstData()
{
if (!m_locks.HasLockRead())
{
return NULL;
}
return &m_data;
}
CCriticalRWLocks m_locks;
private:
DATA m_data;
};
//确保以某种顺序,加锁,解锁 以防止死锁
class CLockUnitManage
{
public:
CLockUnitManage()
{
m_bHasLock = FALSE;
}
void SetLockFlag(SN::IReadWriteLock& lock)
{
if (m_bHasLock)
{
return;
}
m_mLocks[&lock] = 2;
}
void SetLockReadFlag(SN::IReadWriteLock& lock)
{
if (m_bHasLock)
{
return;
}
m_mLocks[&lock] = 1;
}
void BeginLock()
{
if (m_bHasLock)
{
return;
}
m_bHasLock = TRUE;
for (std::map<SN::IReadWriteLock*, int>::const_iterator it = m_mLocks.begin(); it != m_mLocks.end(); ++it)
{
if (2 == it->second)
{
it->first->Lock();
}
else if (1 == it->second)
{
it->first->LockRead();
}
}
}
void EndLock()
{
if (!m_bHasLock)
{
return;
}
m_bHasLock = FALSE;
for (std::map<SN::IReadWriteLock*, int>::const_iterator it = m_mLocks.begin(); it != m_mLocks.end(); ++it)
{
if (2 == it->second)
{
it->first->UnLock();
}
else if (1 == it->second)
{
it->first->UnLockRead();
}
}
}
~CLockUnitManage()
{
EndLock();
}
protected:
std::map<SN::IReadWriteLock*,int> m_mLocks;
bool m_bHasLock;//锁定状态下,解锁前无法 ,增加标志和锁。
};
CLockUnit<CString> g_strName;
CLockUnit<int> g_iAge;
class CTestDeadLock
{
public:
static UINT Test1(LPVOID)
{
CLockUnitManage lockManages;
lockManages.SetLockFlag(g_strName.m_locks);
lockManages.SetLockFlag(g_iAge.m_locks);
lockManages.BeginLock();
CString* pStr = g_strName.GetData();
int* pI = g_iAge.GetData();
*pStr += _T("A");
*pI += 1;
Sleep(1);
return 0;
}
static UINT Test2(LPVOID)
{
CLockUnitManage lockManages;
lockManages.SetLockFlag(g_iAge.m_locks);
lockManages.SetLockFlag(g_strName.m_locks);
lockManages.BeginLock();
CString* pStr = g_strName.GetData();
int* pI = g_iAge.GetData();
*pStr += _T("A");
*pI += 1;
Sleep(1);
return 0;
}
};
}
void CSNMFCDlg::OnBnClickedButton23()
{
for (int i = 0; i < 100; i++)
{
AfxBeginThread(TEST2::CTestDeadLock::Test1,NULL);
AfxBeginThread(TEST2::CTestDeadLock::Test2, NULL);
}
TEST2::CTestDeadLock::Test2(NULL);
}
相关文章
|
7月前
|
监控 算法 安全
|
4月前
死锁原因
死锁原因
46 1
|
7月前
|
安全 算法 程序员
|
7月前
|
SQL 存储 设计模式
如何与死锁斗争!!!
尽量不要改动线上数据库的字段,因为会触发锁表影响业务,严重时还可能出现死锁!数据库真的出现了死锁,业务全挂了,这种时候应该怎么办呢?本文就给大家分享一下数据库死锁的排查思路,万一出了问题,也有底气去解决。
64 1
|
7月前
|
安全 Java 测试技术
发生死锁怎么办
发生死锁怎么办
67 0
|
7月前
死锁的发生与避免
死锁的发生与避免 死锁是指两个或者多个进程在执行过程中,因争夺资源而造成的一种僵局,若无外力作用,它们都将无法推进下去。在计算机系统中,死锁是一种常见的问题,因此需要采取一些措施来避免死锁的发生。
|
算法 安全
死锁的总结(2)
死锁的总结
50 0
|
安全 算法
死锁的总结(1)
死锁的总结
36 0
|
安全 算法
初识死锁问题
关于对死锁的详解
|
算法 调度
死锁
死锁
91 0