앞서 MemoryPool(https://swjman.tistory.com/5) 클래스를 공부하였는데, 그 클래스는 메모리를 연결리스트로 자료구조화하여 관리하기 때문에 멀티스레드 이슈가 발생하게 된다. 이를 극복하기 위하여 본 섹션에서는 explicit locking을 이용하는 방안에 대해 설명하고 있다.


locking 방식은 조금 특이한데, 바로 sync 클래스를 상속 받도록 구현을 한다는 점이다. 그 내용은 대략 아래와 같다.


template <class T>
class CMultiThreadSync
{
friend class CThreadSync;
public:
	class CThreadSync
	{
	public:
		CThreadSync(VOID)
		{
			T::mSync.Enter();
		}

		~CThreadSync(VOID)
		{
			T::mSync.Leave();
		}
	};

private:
	static CCriticalSection mSync;
};


이렇게 템플릿을 이용하여 생성자/소멸자를 이용한 auto lock 시스템 클래스를 만들고, 스레드 동기화가 필요한 클래스에 injection해준다. 인젝션 방식은 아래 예와 같이 상속을 하면 된다.


class CircularQueue : public CMultiThreadSync<CircularQueue>

 

위와 같이 해주고 나서 스레드 안전성이 필요한 함수에 아래와 같이 작업을 해주면 된다.


void Push(int data)
{
	CThreadSync sync;
	// 자동으로 잠김

	...작업 코드...

	// 종료 시 자동으로 풀림
}

 

동작 원리는 C++을 공부한 사람이라면 매우 간단히 파악할 수 있으니, 생략하겠다.


상속을 이용하여 클래스의 성질 자체를 thread-safe하게 만드는 방식은 상당히 독특한데, 문제는 하나의 자료구조 클래스로 다수의 인스턴스를 만들게 되면, lock이 공유가 되어 원하는 동작을 할 수가 없다는 것이다. 예를 들면,


CircularQueue m_MsgQueue;
CircularQueue m_SendQueue;


이렇게 선언을 하고 사용하려 하면, m_MsgQueue와 m_SendQueue가 서로 독립적인 큐 임에도 CMultiThreadSync내에 static인 mSync를 공유하게 되어 임계 영역이 길어지게 되므로, 결국 성능의 이슈로 귀결될 수 있다.

다만, 저자께서 이렇게 시스템을 만든 특별한 이유가 있을 수도 있기 때문에 섣불리 좋다 나쁘다를 판단할 수는 없을 것 같다.
 


Posted by JMAN