| #ifndef CAFFE2_UTILS_SIMPLE_QUEUE_H_ | |
| #define CAFFE2_UTILS_SIMPLE_QUEUE_H_ | |
| #include <condition_variable> // NOLINT | |
| #include <mutex> // NOLINT | |
| #include <queue> | |
| #include "caffe2/core/logging.h" | |
| namespace caffe2 { | |
| // This is a very simple queue that Yangqing wrote when bottlefeeding the baby, | |
| // so don't take it seriously. What it does is a minimal thread-safe queue that | |
| // allows me to run network as a DAG. | |
| // | |
| // A usual work pattern looks like this: one or multiple producers push jobs | |
| // into this queue, and one or multiple workers pops jobs from this queue. If | |
| // nothing is in the queue but NoMoreJobs() is not called yet, the pop calls | |
| // will wait. If NoMoreJobs() has been called, pop calls will return false, | |
| // which serves as a message to the workers that they should exit. | |
| template <typename T> | |
| class SimpleQueue { | |
| public: | |
| SimpleQueue() : no_more_jobs_(false) {} | |
| // Pops a value and writes it to the value pointer. If there is nothing in the | |
| // queue, this will wait till a value is inserted to the queue. If there are | |
| // no more jobs to pop, the function returns false. Otherwise, it returns | |
| // true. | |
| bool Pop(T* value) { | |
| std::unique_lock<std::mutex> mutex_lock(mutex_); | |
| while (queue_.size() == 0 && !no_more_jobs_) cv_.wait(mutex_lock); | |
| if (queue_.size() == 0 && no_more_jobs_) return false; | |
| *value = queue_.front(); | |
| queue_.pop(); | |
| return true; | |
| } | |
| int size() { | |
| std::unique_lock<std::mutex> mutex_lock(mutex_); | |
| return queue_.size(); | |
| } | |
| // Push pushes a value to the queue. | |
| void Push(const T& value) { | |
| { | |
| std::lock_guard<std::mutex> mutex_lock(mutex_); | |
| CAFFE_ENFORCE(!no_more_jobs_, "Cannot push to a closed queue."); | |
| queue_.push(value); | |
| } | |
| cv_.notify_one(); | |
| } | |
| // NoMoreJobs() marks the close of this queue. It also notifies all waiting | |
| // Pop() calls so that they either check out remaining jobs, or return false. | |
| // After NoMoreJobs() is called, this queue is considered closed - no more | |
| // Push() functions are allowed, and once existing items are all checked out | |
| // by the Pop() functions, any more Pop() function will immediately return | |
| // false with nothing set to the value. | |
| void NoMoreJobs() { | |
| { | |
| std::lock_guard<std::mutex> mutex_lock(mutex_); | |
| no_more_jobs_ = true; | |
| } | |
| cv_.notify_all(); | |
| } | |
| private: | |
| std::mutex mutex_; | |
| std::condition_variable cv_; | |
| std::queue<T> queue_; | |
| bool no_more_jobs_{}; | |
| // We do not allow copy constructors. | |
| SimpleQueue(const SimpleQueue& /*src*/) {} | |
| }; | |
| } // namespace caffe2 | |
| #endif // CAFFE2_UTILS_SIMPLE_QUEUE_H_ |