#include "pch.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <future>
#include "windows.h"
using namespace std;
queue<int32> q;
stack<int32> s;
void push()
{
while (true)
{
int32 value = rand() % 10;
q.push(value);
this_thread::sleep_for(10ms);
}
}
void pop()
{
while (true)
{
if (q.empty())
{
continue;;
}
int32 data = q.front();
q.pop();
cout << data << endl;
}
}
int main()
{
thread t1(push);
thread t2(pop);
t1.join();
t2.join();
return 0;
}
이 코드는 문제가 있는 코드로 크래쉬가 발생 할수 있다 => 동기화 처리가 되어 있지 않음
LockStack
이걸 좀 해결해 보면 다음 처럼 해결 해 볼 수 있을것이다
#pragma once
#include <mutex>
template<typename T>
class LockStack
{
public :
LockStack() = default;
LockStack(const LockStack&) = delete;
LockStack& operator=(const LockStack&) = delete;
void push(T value)
{
lock_guard<mutex> lock(_mutex);
_stack.push( std::move(value));
_conVar.notify_one();
}
bool tryPop(T& value)
{
lock_guard<mutex> lock(_mutex);
if (_stack.empty())
{
return false;
}
value = std::move(_stack.top());
_stack.pop();
return true;
}
//pop 할 데이터가 없을때 대기하다가 pop 할 데이터가 생기면 그때 pop하고 끝내는 함수
void waitPop(T& value)
{
unique_lock<mutex> lock(_mutex);
// stack 이 비어있지 않다면(false) == false => true
// stack 이 비어 있다면 (true) == false => false , 조건이 만족하지 않으면 lock 을 풀고 sleep 하게 된다
_conVar.wait(lock, [this] { return _stack.empty() == false; });
value = std::move(_stack.top());
_stack.pop();
}
private :
stack<T> _stack;
mutex _mutex;
condition_variable _conVar;
};
#include "pch.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <future>
#include "windows.h"
#include "ConcurrentStack.h"
using namespace std;
queue<int32> q;
stack<int32> s;
LockStack<int> st;
void push()
{
int i = 0;
while (true)
{
st.push(i++);
this_thread::sleep_for(10ms);
}
}
void pop()
{
while (true)
{
int popData = 0;
if (st.tryPop(popData))
{
cout << popData << endl;
}
}
}
int main()
{
thread t1(push);
thread t2(pop);
t1.join();
t2.join();
return 0;
}
실행 결과는 다음과 같다
데이터를 꺼낼때 여기에서 따로 구현하게 되는 Empty 함수를 호출 체크하는게 의미가 없는데, Empty 함수안에
lock_guard 가 있고 Empty 함수가 끝난 이후 Pop 함수로 되돌아 갈때
다른 스레드에서 stack 에 데이터를 추가하거나 제거 하게 된다면 현재 스레드에서 pop 을 할때
스택이 비어 있는지 차 있는지 알수 없음으로 (그 순간 사이에서) 무의미하다
그래서 pop 할때 empty 함수를 호출하지 않고 내부에 구현한다, 유저 편의상 Empty 함수를 제공해 줄 순 있겠지만..
코드 중 _conVar.notify_one(); 가 있는 이유는
waitPop 떄문인데 stack 에 데이터가 없다면 대기했다가 notifiy 가왔을때 데이터가 존재하면 스레드가 깨어나 데이터를 pop 한다음 출력하기 위함이다
결과는 동일하다
반응형
'운영체제 & 병렬처리 > Multithread' 카테고리의 다른 글
LockFree - Stack (1) (0) | 2022.09.15 |
---|---|
LockBase Queue (0) | 2022.09.14 |
TLS(Thread Local Storage) : thread_local (0) | 2022.09.14 |
Sequential consistency (순차 일관성) (0) | 2022.09.13 |
Singleton multithreading programs (2) (0) | 2022.09.13 |