#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

+ Recent posts