락기반의 스택, 큐
일반적인 스택 큐를 사용할때랑 멀티스레드 프로그래밍에서 스택 큐를 사용때는 조금 다르다..
empty체크에서 1개가 남아있을 경우 비어있지 않다고 말해줄 수 있을텐데 만약 그순간에 다른 스레드가 pop을 하면 이것은 비어있는 현상이 된다..
락기반 큐 헤더 부분
#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();
}
//TryPop 대체용
void WaitPop(T& value)
{
unique_lock<mutex> lock(_mutex);
_condVar.wait(lock, [this] {return _queue.empty() == false; }); // 조건에 맞을때까지 wait..
value = std::move(_queue.front());
_queue.pop();
}
//데이터가 없더라도 데이가 있는지 없는지 체크를 해야서 계속해서 TryPop을 해야한다 SPINLOCK 느낌..
bool TryPop(T& value)
{
lock_guard<mutex> lock(_mutex);
if (_queue.empty()) return false;
value = std::move(_queue.front());
_queue.pop();
return true;
}
public:
queue<T> _queue;
mutex _mutex;
condition_variable _condVar;
};
이 소스에서 TryPop과 WaitPop의 차이를 보자. !
TryPop에서는 empty인지 계속해서 체크한다 그런데 계속 데이터를 넣지 않고 있을 경우 이 체크는 무의미한 것이다. 이것은 spinlock과 비슷하네..
- 그래서 TryPop의 이러한 무의미한 반복을 막기 위해서 WaitPop이 생겼다. WaitPop은 condition_variable을 통해 조건을 줘서 조건이 맞을때까지 wait를 하도록 시켜서 무의미하게 체크를 하지않아도 된다. 여기서 unique_lock을 쓴 이유는 상태변수를 사용하기 위해서이다.
TryPop의 주소 value부분
bool TryPop(T& value)
{
lock_guard<mutex> lock(_mutex);
if (_stack.empty()) return false;
value = std::move(_stack.top());
_stack.pop();
return true;
}
- 일반적인 pop에서는 매개변수 인자가 필요가 없다 그렇지만 여기서는 value를 넣었는데 이유가 멀까 싶었는데 main부분에서 data를 꺼내오기 위함이었다 그래서 받아올때도 &로 받아오면서 데이터를 넣는다.
락기반 스택 부분
- 큐 부분과 동일하다.
#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)); //이동 성능 향상
_cv.notify_one();
}
//TryPop 대체용
void WaitPop(T& value)
{
unique_lock<mutex> lock(_mutex);
_cv.wait(lock, [this] {return _stack.empty() == false; }); // 조건에 맞을때까지 wait..
value = std::move(_stack.top());
_stack.pop();
}
//데이터가 없더라도 데이가 있는지 없는지 체크를 해야서 계속해서 TryPop을 해야한다 SPINLOCK 느낌..
bool TryPop(T& value)
{
lock_guard<mutex> lock(_mutex);
if (_stack.empty()) return false;
value = std::move(_stack.top());
_stack.pop();
return true;
}
/*
* 멀티스레드 환경에서는 엠피가 큰 효과가 없다 이유는 현재 엠티가 아니라고 체크 한후 pop을 할려고했는데
* 그 사이에 다른 스레드가 와서 나머지를 가져간다면 엠티가 되기때문...
*/
bool Empty()
{
lock_guard<mutex> lock(_mutex);
}
private:
stack<T> _stack;
mutex _mutex;
condition_variable _cv;
};
- 루키스님의 서버강의를 수강 후 학습하여 작성하였습니다.
'멀티쓰레드프로그래밍' 카테고리의 다른 글
Future (0) | 2022.04.07 |
---|---|
cpu 파이프라인 (0) | 2022.04.07 |
캐시, 메모리 계층 (0) | 2022.04.06 |
TLS (ThreadLocalStorage) (0) | 2022.04.06 |
메모리 모델 (0) | 2022.03.30 |