CRITICAL_SECTION同步易出错的地方

众所周知通过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、后记:以上是最简单的锁实现,加锁和解锁往往导致效率低下,以此改进,使用读写锁、闩锁等不同的加锁粒度来提升性能。



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值