queue, stack
을 concurrecy환경에서 안전하게 읽고/쓰고를 해보자.
Stack 구현
#pragma once
#include <mutex>
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));
// (참고) std::move == static_cast<T&&>() 임을 기억하자
_condVar.notify_one();
}
bool TryPop(T& value)
{
lock_guard<mutex> lock(_mutex);
if (_stack.empty())
return false;
// empty -> top -> pop
value = std::move(_stack.top());
_stack.pop();
return true;
}
void WaitPop(T& value)
{
unique_lock<mutex> lock(_mutex);
// empty 상태를 확인, condition_variable이용
// Trypop은 무한으로 대기하는 버전이고,
// WaitPop은 Push되면 동작하는 버전
_condVar.wait(lock, [this] { return _stack.empty() == false; });
value = std::move(_stack.top());
_stack.pop();
}
private:
stack<T> _stack;
mutex _mutex;
condition_variable _condVar;
};
queue 구현
#pragma once
#include <mutex>
template<typename T>
class LockQueue
{
public:
LockQueue() { }
LockQueue(const LockQueue&) = delete;
LockQueue& operator=(const LockQueue&) = delete;
void Push(T value)
{
lock_guard<mutex> lock(_mutex);
_queue.push(std::move(value));
_condVar.notify_one();
}
bool TryPop(T& value)
{
lock_guard<mutex> lock(_mutex);
if (_queue.empty())
return false;
value = std::move(_queue.front());
_queue.pop();
return true;
}
void WaitPop(T& value)
{
unique_lock<mutex> lock(_mutex);
_condVar.wait(lock, [this] { return _queue.empty() == false; });
value = std::move(_queue.front());
_queue.pop();
}
private:
queue<T> _queue;
mutex _mutex;
condition_variable _condVar;
};