Created
June 23, 2015 07:51
-
-
Save carlchen0928/0d0d9e8f59728a4872f3 to your computer and use it in GitHub Desktop.
thread safe queue with condition_variable and mutex
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <queue> | |
| #include <mutex> | |
| #include <memory> | |
| #include <condition_variable> | |
| #include <stdio.h> | |
| #include <iostream> | |
| /* | |
| * thread safe queue implementation. | |
| * Use a mutex and condition_variable to keep thread safe. | |
| * When queue is empty, wait_and_pop function will block | |
| * until queue has item. try_pop function will return false | |
| * when queue empty. | |
| * I provide two way to pop item from queue. Reference parameter | |
| * or shared_ptr return value. | |
| * Length of queue is unlimited. | |
| */ | |
| #define DEBUG | |
| template <class T> | |
| class threadsafe_queue | |
| { | |
| public: | |
| threadsafe_queue() {}; | |
| threadsafe_queue(const threadsafe_queue& other); | |
| threadsafe_queue& operator=(const threadsafe_queue&); | |
| void push(T value) | |
| { | |
| std::lock_guard<std::mutex> lg(mtx); | |
| Q.push(value); | |
| cv.notify_one(); | |
| #ifdef DEBUG | |
| std::cout << "push " << value << std::endl; | |
| #endif | |
| } | |
| bool try_pop(T& value) | |
| { | |
| { | |
| std::lock_guard<std::mutex> lg(mtx); | |
| if (Q.empty()) { | |
| #ifdef DEBUG | |
| std::cout << "try_pop but empty" << std::endl; | |
| #endif | |
| return false; | |
| } | |
| value = Q.front(); | |
| Q.pop(); | |
| } | |
| #ifdef DEBUG | |
| std::cout << "try_pop " << value << std::endl; | |
| #endif | |
| return true; | |
| } | |
| std::shared_ptr<T> try_pop() | |
| { | |
| { | |
| std::lock_guard<std::mutex> lg(mtx); | |
| if (Q.empty()) { | |
| #ifdef DEBUG | |
| std::cout << "try_pop but empty" << std::endl; | |
| #endif | |
| return std::shared_ptr(); | |
| } | |
| std::shared_ptr<T> ptr( | |
| std::make_shared<T>(Q.front())); | |
| Q.pop(); | |
| } | |
| #ifdef DEBUG | |
| std::cout << "try_pop " << *ptr << std::endl; | |
| #endif | |
| return ptr; | |
| } | |
| void wait_and_pop(T& value) | |
| { | |
| std::unique_lock<std::mutex> ul(mtx); | |
| cv.wait(ul, [this](){ | |
| return !Q.empty(); | |
| }); | |
| value = Q.front(); | |
| Q.pop(); | |
| #ifdef DEBUG | |
| std::cout << "wait_and_pop " << value << std::endl; | |
| #endif | |
| } | |
| std::shared_ptr<T> wait_and_pop() | |
| { | |
| std::unique_lock<std::mutex> ul(mtx); | |
| cv.wait(ul, [this](){ | |
| return !Q.empty(); | |
| }); | |
| std::shared_ptr<T> ptr( | |
| std::make_shared<T>(Q.front())); | |
| Q.pop(); | |
| #ifdef DEBUG | |
| std::cout << "wait_and_pop " << *ptr << std::endl; | |
| #endif | |
| return ptr; | |
| } | |
| bool empty() const | |
| { | |
| std::lock_guard<std::mutex> lg(mtx); | |
| return Q.empty(); | |
| } | |
| size_t size() const | |
| { | |
| std::lock_guard<std::mutex> gl(mtx); | |
| return Q.size(); | |
| } | |
| private: | |
| std::queue<T> Q; | |
| std::mutex mtx; | |
| std::condition_variable cv; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment