Last active
August 29, 2015 14:23
-
-
Save carlchen0928/d6b38f1a0536d691e860 to your computer and use it in GitHub Desktop.
thread safe && exception safe queue
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 && exception safe queue implementation. | |
| * Save item in shared_ptr in the queue to make sure all | |
| * construction called in push function, when exception | |
| * happened, nothing will change and data still in consistence. | |
| * If we construct object in pop functions, when exception happened, | |
| * things already pop from queue, behavior undefined. | |
| * Base on threadsafe_queue. | |
| */ | |
| #define DEBUG | |
| template <class T> | |
| class threadsafe_exceptionsafe_queue | |
| { | |
| public: | |
| threadsafe_exceptionsafe_queue() {}; | |
| threadsafe_exceptionsafe_queue(const threadsafe_exceptionsafe_queue& other); | |
| threadsafe_exceptionsafe_queue& operator=(const threadsafe_exceptionsafe_queue&); | |
| void push(T value) | |
| { | |
| shared_ptr<T> ptr( | |
| make_shared<T>(std::move(value))); | |
| std::lock_guard<std::mutex> lg(mtx); | |
| Q.push(ptr); | |
| 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 = std::move(*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 = 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 = std::move(*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 = 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<shared_ptr<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