LOGIN • JOININ

LOCK

[Tutorials/[Common] 1. Object System/Tutorial_Object04_TimeAndTime]


1... Lockable의 선언

 CRITICAL_SECTION을 사용해 편리하게 LOCK을 구현하기 위해 템플릿 클래스인 LOCKABLE<>을 제공합니다.

LOCKABLE<>은 상속을 받을 수 있는 어떤 형(Type)에서도 사용할 수 있습니다.

예를 들어...

LOCKABLE<vector<int>>	a; // vector<int>형의 변수에 락기능을 추가했다.
LOCKABLE<foo>			  b; // foo형 변수에 락 기능을 추가했다.
LOCKABLE<>			  c; // 아무것도 없을 경우 그냥 락 객체만 생성한다.

a는 vector<int>형 클래스로 선언되었습니다. 다만 락이 가능하다는 것만 추가된 것입니다.

또 foo형인 a변수 역시 foo형인데 락이 가능하다는 것만 추가되었습니다.

아무런 변수 없이 그냥 LOCKABLE<>만 있을 경우 락 기능만 존재합니다.

따라서 LOCKABLE로 선언된 변수들은 락이 가능합니다.

a.lock()

for(auto& iter:a)
{
	if(iter==0)
		return;
}

a.unlock()


이런 식의 사용이 가능합니다.



2... 안전한 Lock처리

위와 같이 작성을 하게 될 경우 for문을 돌다 그냥 리턴해 버리면 unlock()이 호출되지 않고 끝나 버려 심각한 문제가 발생합니다.

그래서 아래와 같이 return하기 전에 반드시 unlock()을 호출하고 return하도록 해야할 것입니다.


a.lock()
for(auto& iter:a)
{
	if(iter==0)
	{
		a.unlock();
		return;
	}
}
a.unlock()


하지만 이렇게 작업했다해도 예외가 던져져 버리는 경우 그냥 리턴해 버리는 경우가 있을 수 있습니다. 

그렇다면 또 아래와 같이 예외를 처리해 주는 코드를 추가해야 할 것입니다.


a.lock()

try
{
	for(auto& iter:a)
	{
		if(iter==0)
		{
			a.unlock();
			return;
		}
	}
}
catch(...)
{
	a.unlock();
	throw;
}

a.unlock()



3... Scoped Lock
일반적으로 그냥 락을 그대로 사용해 사용할 경우 이런 식으로 복잡해 질수 있기 때문에 범위 락(Scoped Lock)을 사용합니다.
CGCII의 범위 락은 아래와 같이 LOCK_BEGIN과 LOCK_END을 사용하면 간단히 사용할 수 있습니다.


LOCK_BEGIN(a)
{
	for(auto& iter:a)
	{
		if(iter==0)
			return;
	}
}
LOCK_END

혹은

LOCK(a)
{
	for(auto& iter:a)
	{
		if(iter==0)
			return;
	}
}

이렇게 작성할 경우 중간에 리턴되어 나가거나 예외가 던져저 빠저나가게 되더라도 자동적으로 Lock을 해제하고 빠져 나가도록 처리가 됩니다.