Skip to content

Commit

Permalink
feat(c++/multi-thread-programming): add lock queue/stack examples
Browse files Browse the repository at this point in the history
  • Loading branch information
bugoverdose committed Dec 15, 2024
1 parent 1bbb8ca commit 27bdf91
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 0 deletions.
90 changes: 90 additions & 0 deletions c++/multi-thread-programming/ex24_lock_queue.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#include <iostream>
#include <atomic>
#include <queue>
#include <mutex>
#include <future>
#include <thread>

using namespace std;

#define OUT

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;
};

LockQueue<int> q;

void Push()
{
while (true)
{
int value = rand() % 100;
q.Push(value);

this_thread::sleep_for(chrono::milliseconds(10));
}
}

void Pop()
{
while (true)
{
int data = 0;
if (q.TryPop(OUT data))
cout << data << endl;
// q.WaitPop(OUT data);
// cout << data << endl;
}
}

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

t1.join();
t2.join();
t3.join();
}
92 changes: 92 additions & 0 deletions c++/multi-thread-programming/ex24_lock_stack.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#include <iostream>
#include <atomic>
#include <stack>
#include <mutex>
#include <future>
#include <thread>

using namespace std;

#define OUT

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();
}

bool TryPop(T& value)
{
lock_guard<mutex> lock(_mutex);
// NOTE: Empty 함수 호출 후 Pop을 호출하는 구조가 아니라, 락을 잡고 Empty인지 체크 + Pop 시도까지 함께 진행.
if (_stack.empty())
return false;

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

void WaitPop(T& value)
{
unique_lock<mutex> lock(_mutex);
// 비어있지 않은 경우(empty == false) 통과. 비어있는 동안에는 쓰레드를 대기 상태로 전환.
_condVar.wait(lock, [this] { return _stack.empty() == false; });

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

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

LockStack<int> s;

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

this_thread::sleep_for(chrono::milliseconds(10));
}
}

void Pop()
{
while (true)
{
int data = 0;
if (s.TryPop(OUT data))
cout << data << endl;
// s.WaitPop(OUT data);
// cout << data << endl;
}
}

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

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

0 comments on commit 27bdf91

Please sign in to comment.