Lock Based Stack

Date:     Updated:

카테고리:

태그:

인프런에 있는 루키스님의 게임 서버 강의를 듣고 정리한 내용입니다.


STL

당연한 이야기지만 STL 자료구조는 멀티쓰레드 환경에서 정상적으로 작동하지 않는다. Vector의 경우를 생각해보자. 가장 먼저 여러 개의 쓰레드에서 같은 iterator 위치에 접근할 수 있다. 또한 vector의 경우 capacity가 초과되면 새로운 vector를 생성하고 데이터를 옮긴 뒤, 기존 메모리를 삭제한다. 이때 서로 다른 쓰레드에서 새로운 컨테이너를 생성한 뒤 각자 기존 메모리를 삭제하려 하면 double-free 문제가 발생하게 된다.



stack<int32> s;

void Push()
{
	while (true) {
		int32 value = rand() % 100;
		s.push(value);

		this_thread::sleep_for(10ms);
	}
}

void Pop()
{
	while (true) {
		if (s.empty())
			continue;

		int32 data = s.top();
		s.pop();
		cout << data << endl;
	}
}

int main()
{
	thread t1(Push);
	thread t2(Pop);
	thread t3(Pop);

	t1.join();
	t2.join();
	t3.join();
}

thread17

Stack의 경우도 마찬가지이다. 멀티 쓰레드 환경에서도 정상적으로 작동하는 Lock Based Stack을 구현해보자.


Lock Based Stack

SpinLock 방식


template<typename T>
class LockStack
{
public:
	LockStack() {}

	LockStack(const LockStack&) = delete;
	LockStack& operator=(const LockStack&) = delete;

	void Push(T value)
	{
		lock_guard<mutex> lock(_mutex);
		_stack.push(std::move(value));
	}

	bool TryPop(T& value)
	{
		lock_guard<mutex> lock(_mutex);
		if (_stack.empty())
			return false;

		value = std::move(_stack.top());
		_stack.pop();
		return true;
	}

private:
	stack<T> _stack;
	mutex _mutex;
};

  • Stack의 소유권을 분명히 하기 위해 복사 생성자, 복사 대입 연산자는 막아 놓음
  • 일반적으로 Pop은 empty를 확인 후 해야하는데, 멀티쓰레드 환경에서 empty를 따로 구현해 놓는 것은 의미가 없음
    • empty체크 & Pop이 원자적으로 이루어져야 하기 때문에 TryPop()에서 한 번에 구현
  • 혹시 모르니 데이터는 std::move로 받아오기


Event 방식


template<typename T>
class LockStack
{
public:
	LockStack() {}

	LockStack(const LockStack&) = delete;
	LockStack& operator=(const LockStack&) = delete;

	void Push(T value)
	{
		lock_guard<mutex> lock(_mutex);
		_stack.push(std::move(value));
        _condVar.notify_one();
	}

	void WaitPop(T& value)
	{
		unique_lock<mutex> lock(_mutex);

		_condVar.wait(lock, [this] {return _stack.empty() == false; });
		value = std::move(_stack.top());
		_stack.pop();
	}

private:
	stack<T> _stack;
	mutex _mutex;
	condition_variable _condVar;
};

  • 이전에 배운 condition_variable을 이용해 이벤트 방식으로도 구현이 가능



맨 위로 이동하기

Server 카테고리 내 다른 글 보러가기

댓글 남기기