diff --git a/c++/multi-thread-programming/ex24_lock_queue.cpp b/c++/multi-thread-programming/ex24_lock_queue.cpp new file mode 100644 index 0000000..352e34a --- /dev/null +++ b/c++/multi-thread-programming/ex24_lock_queue.cpp @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define OUT + +template +class LockQueue +{ +public: + LockQueue() { } + + // 복사하지 못하도록 막음 + LockQueue(const LockQueue&) = delete; + LockQueue& operator=(const LockQueue&) = delete; + + void Push(T value) + { + lock_guard lock(_mutex); + _queue.push(std::move(value)); + + _condVar.notify_one(); + } + + bool TryPop(T& value) + { + lock_guard lock(_mutex); + if (_queue.empty()) + return false; + + value = std::move(_queue.front()); + _queue.pop(); + return true; + } + + void WaitPop(T& value) + { + unique_lock lock(_mutex); + _condVar.wait(lock, [this] { return _queue.empty() == false; }); + + value = std::move(_queue.front()); + _queue.pop(); + } + +private: + queue _queue; + mutex _mutex; + condition_variable _condVar; +}; + +LockQueue 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(); +} diff --git a/c++/multi-thread-programming/ex24_lock_stack.cpp b/c++/multi-thread-programming/ex24_lock_stack.cpp new file mode 100644 index 0000000..efec804 --- /dev/null +++ b/c++/multi-thread-programming/ex24_lock_stack.cpp @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define OUT + +template +class LockStack +{ +public: + LockStack() { } + + // 복사하지 못하도록 막음 + LockStack(const LockStack&) = delete; + LockStack& operator=(const LockStack&) = delete; + + void Push(T value) + { + lock_guard lock(_mutex); + _stack.push(std::move(value)); + + _condVar.notify_one(); + } + + bool TryPop(T& value) + { + lock_guard 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 lock(_mutex); + // 비어있지 않은 경우(empty == false) 통과. 비어있는 동안에는 쓰레드를 대기 상태로 전환. + _condVar.wait(lock, [this] { return _stack.empty() == false; }); + + value = std::move(_stack.top()); + _stack.pop(); + } + +private: + stack _stack; + mutex _mutex; + condition_variable _condVar; +}; + +LockStack 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(); +}