Deadlock is the most common case

Wait for each other.

A business that

For simple businesses, it is possible to specify that only one cell can be locked at a time, but for complex businesses, this approach is not feasible. For example: gold and silver swap, 1 gold for 10 silver. There are 4 steps: 1, judge the gold is enough. 2. Judge that the silver coin has not reached the upper limit 3, and the gold coin decreases. 4. Increased credits. Suppose there is only one gold coin, thread one performs step one, finds enough gold, and happens to be suspended; Thread two performs step one and finds that the gold is sufficient. So the gold becomes minus 1. To avoid this, gold and silver must be locked up at the same time. Function 1, first lock gold, then lock silver; Function two, first lock silver, then lock gold. Thread 1, lock gold, want to lock silver; Thread two, lock silver, want to lock gold.

The test code

namespace TEST1 {

Class CTestDeadLock {public: static UINT Test1(LPVOID) {// 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); }

 

The solution

The Sleep(1) above is meant to simulate being accidentally suspended. Solution to deadlocks: Lock in a specific order. If there are many cells to lock, the caller has no way of knowing. Lock that one first.

Lock management class

Set the flag first, Lock automatically in sequence.

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 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
<: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::mapSN::IReadWriteLock*,int m_mLocks; bool m_bHasLock; // Add flags and locks before unlocking. };
*,>

CLockUnit g_strName; CLockUnit 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); }