bdfgdfg

[온라인 서버] 네트워크 라이브러리 - Monitor Class 본문

게임프로그래밍/서버 책

[온라인 서버] 네트워크 라이브러리 - Monitor Class

marmelo12 2022. 1. 4. 18:21
반응형

Monitor Class

- 이 클래스는 동기화 객체로서 CRITICAL_SECTION(유저모드 동기화)객체를 사용하기 편하도록 초기화와 해제를 생성자와 소멸자로 빼내어 사용자가 따로 하지 않아도 자동으로 되게 만든다. -> 모던 C++에선 lock_guard같은 역할.

 -> 교착 상태(DeadLock)과 기아 상태(Starvation)을 미연에 방지하도록 설계

- 사용할 때엔 동기화가 필요한 클래스는 이 클래스를 상속받아 사용한다.

 

#pragma once
#include "std.h"

// 복사되는것을 방지.
class Monitor
{
public:
	class Owner
	{
	// Owner클래스는 자동으로 CS객체의 소유권을 해제하기 위해 만들어짐

	public:
		Owner(Monitor& crit);
		~Owner();
	private:
		Monitor& m_csSyncObject;
		Owner(const Owner& rhs);
		Owner& operator=(const Owner& rhs);
	};
	Monitor();
	~Monitor();
	BOOL TryEntry();

	// Enter와 Leave는 각각 락을걸고 해제하는 역할.
	// 밑의 m_csObject가 대상.
	void Enter();
	void Leave();
private:
	CRITICAL_SECTION m_csObject;
	Monitor(const Monitor& rhs);
	Monitor& operator=(const Monitor& rhs);
};
#include "Monitor.h"

Monitor::Monitor()
{
	::InitializeCriticalSection(&m_csObject);
}

Monitor::~Monitor()
{
	// 생성한 csObject 리소스 반환.
	::DeleteCriticalSection(&m_csObject);
}

BOOL Monitor::TryEntry()
{
	// TryEnterCriticalSection는 진입이 가능하면 True를 반환하면서 진입.
	// 진입이 불가능하면 곧바로 false반환 후 대기하지 않고 넘어간다.
	// EnterCriticalSection은 임계영역의 락을 획득할때까지 작업을 block.
	// TryEnterCriticalSection는 락이 획득 가능하던 아니던 결과를 즉시 반환.
	return ::TryEnterCriticalSection(&m_csObject);
}

void Monitor::Enter()
{
	::EnterCriticalSection(&m_csObject);
}

void Monitor::Leave()
{
	::LeaveCriticalSection(&m_csObject);
}

Monitor::Owner::Owner(Monitor& crit) :m_csSyncObject(crit)
{
	m_csSyncObject.Enter();
}

Monitor::Owner::~Owner()
{
	m_csSyncObject.Leave();
}

TryEnter함수는 내부적으로 TryEnterCriticalSection함수를 이용해 CS객체의 소유권을 획득하는데

이 함수는 CS객체의 소유권을 다른 쓰레드가 이미 소유하고 있다면 바로 대기 상태(Block)로 빠지지 않고 사용자가

설정해준 횟수만큼 소유권을 가져오려 시도한다.

 -> 이런것을 스핀락(SpinLock)이라 하는데 최대한 CPU를 다른 쓰레드에 넘기지않고 진입이 가능한지 반복해서 확인하는 방법이다.

 

Monitor 클래스안에 Owner클래스를 만든 이유는 자동으로 락을 해제하기 위해 만들었는데,

Monitor클래스의 생성자와 소멸자에서는 CS객체의 초기화와 반납(해제)를 담당하고

Owner클래스의 생성자와 소멸자에선 Monitor클래스의 객체를 이용해 락을 걸고 해제를 한다.

 

즉 Monitor클래스에서는 생성자와 소멸자를 이용해 자동으로 CS객체의 초기화와 해제를 진행하고

Owner클래스에서는 생성자와 소멸자를 이용해 자동으로 락을 걸고 해제를 한다.

 -> 클래스의 객체가 생성될때와 소멸될때 생성자와 소멸자가 호출된다는 점을 이용한 것.

 

Monitor클래스를 이용한 예제를 보자.

#include "Monitor.h"

class SyncClass : public Monitor
{
public:
    SyncClass();
    ~SyncClass();
    void IncrementInteger();

private:
    int     m_integer;
    Monitor m_csObject;
};
SyncClass::SyncClass() : m_integer(0)
{
    
}

SyncClass::~SyncClass()
{
}

void SyncClass::IncrementInteger()
{
    // 모니터 객체를 넘겨준다. 
    // Owner의 생성자에 모니터 객체 넘길시 자동으로 락을 건다.
    Owner lock(m_csObject);
    m_integer++;
    
    // 이 함수를 빠져나오면 자동으로 Owner의 소멸자가 호출되어
    // LeaveCriticalSection 함수가 호출된다.
}

 

반응형
Comments