C++基础之使用构造和析构函数保证成对出现

 

如果想要某些事情成对出现,使用构造函数和析构函数。

 

为保证线程同步/互斥,经常使用信号量、互斥量、临界区和事件。以临界区 CRITICAL_SECTION 为例,需要

InitializeCriticalSection 和 DeleteCriticalSection

EnterCriticalSection 和 LeaveCriticalSection

成对配合使用,否则可能出现资源泄漏甚至死锁的情况。

考虑以下程序片段,中间的代码可能出现异常,导致控制转移。或者函数有多个出口,就需要在每个出口前调用LeaveCriticalSection。

CRITICAL_SECTION _cs;
void SomeFunc()
{
	EnterCriticalSection(&_cs);

	//可能抛出异常

	LeaveCriticalSection(&_cs);
}


我们希望EnterCriticalSection(或者其他lock 函数)和 LeaveCriticalSection(或者其他unlock 函数)成对出现,最好的方法是用class来包装,且分别在构造函数和析构函数中实现。

#include <Windows.h>

class Lock
{
public:
	Lock();
	~Lock();
	void Enter(int id = 0);
	void Leave();
private:
	CRITICAL_SECTION _cs;
	DWORD dwOwningThread;
	int iEnterCount;
	int iId;
};

class AutoLock
{
public:
	AutoLock(Lock* target, int id = 0);
	~AutoLock();
private:
	Lock* _target;
};

 

#include "AutoLock.h"

Lock::Lock(): dwOwningThread(0), iEnterCount(0), iId(0)
{
	InitializeCriticalSection(&_cs);
}

Lock::~Lock()
{
	DeleteCriticalSection(&_cs);
}

void Lock::Enter(int id)
{
	DWORD currentThread = GetCurrentThreadId();
	EnterCriticalSection(&_cs);
	dwOwningThread = currentThread;
	iEnterCount++;
	iId = id;
}

void Lock::Leave()
{
	if (--iEnterCount == 0) {
		dwOwningThread = 0;
		iId = 0;
	}
	LeaveCriticalSection(&_cs);
}

AutoLock::AutoLock(Lock* target, int id) : _target(target)
{
	_target->Enter(id);
}

AutoLock::~AutoLock()
{
	_target->Leave();
}


直接使用 AutoLock 类,而不用考虑释放临界区的问题。

	Lock* workBufferLock;
	//...
	AutoLock lock(workBufferLock);
	//...


这个方法应用在很多场合,比如网络访问中建立连接和断开连接,数据库访问中的登录和登出,测量函数平均运行耗时等。

 

【参考】

Solmyr 的小品文系列之六:成对出现

你可能感兴趣的:(C++,数据库,网络,Class)