众所周知通过CRITICAL_SECTION可以对多个线程同步,然而加锁和解锁的次数不匹配将导致死锁:
class CLock
{
public:
CLock()
{
InitializeCriticalSection(&m_cs);
}
~CLock()
{
DeleteCriticalSection(&m_cs);
}
void Lock()
{
EnterCriticalSection(&m_cs);
}
void Unlock()
{
LeaveCriticalSection(&m_cs);
}
private:
CRITICAL_SECTION m_cs;
};
int _tmain(int argc, _TCHAR* argv[])
{
unsigned ThreadId1, ThreadId2;
HANDLE hThread1, hThread2;
hThread1 = (HANDLE)_beginthreadex(0, 0, ThreadFun, NULL, 0, &ThreadId1);
Sleep(1000);
hThread2 = (HANDLE)_beginthreadex(0, 0, ThreadFun, NULL, 0, &ThreadId2);
getchar();
InterlockedCompareExchange(&gExit, 1, gExit);
WaitForSingleObject(hThread1, -1);
WaitForSingleObject(hThread2, -1);
return 0;
}
1、线程A加锁两次、解锁一次,将导致线程B一直不能获得锁:
long gExit = 0;
CLock gLock;
unsigned int _stdcall ThreadFun(void* argv)
{
while (true)
{
gLock.Lock();
gLock.Lock();
if (InterlockedCompareExchange(&gExit, gExit, 0))
{
return 0;
gLock.Unlock();
}
printf("Thread(%d) is Running\n", GetCurrentThreadId());
gLock.Unlock();
//gLock.Unlock();
Sleep(100);
}
}
2、线程A加锁一次,解锁两次,当线程A下次再试图获得锁,将不能获取的到陷入死等,也将导致死锁,同理线程B。:
unsigned int _stdcall ThreadFun(void* argv)
{
while (true)
{
// 加锁一次
gLock.Lock();
//gLock.Lock();
if (InterlockedCompareExchange(&gExit, gExit, 0))
{
return 0;
gLock.Unlock();
}
printf("Thread(%d) is Running\n", GetCurrentThreadId());
// 解锁两次,下次gLock.Lock()将陷入死等
gLock.Unlock();
gLock.Unlock();
Sleep(100);
}
}
3、解决,可以定义一个自动获得锁,保证加锁和解锁完全匹配:
class AutoLock
{
public:
AutoLock()
{
m_lock.Lock();
}
~AutoLock()
{
m_lock.Unlock();
}
private:
CLock m_lock;
private:
AutoLock(const AutoLock& lock);
AutoLock& operator=(const AutoLock& lock);
};
unsigned int _stdcall ThreadFun(void* argv)
{
while (true)
{
AutoLock auto_lock;
if (InterlockedCompareExchange(&gExit, gExit, 0))
{
return 0;
}
printf("Thread(%d) is Running\n", GetCurrentThreadId());
Sleep(100);
}
}
4、后记:以上是最简单的锁实现,加锁和解锁往往导致效率低下,以此改进,使用读写锁、闩锁等不同的加锁粒度来提升性能。