QueuePair与Body是DataReader的内部类。一个DataReader对应一个任务,一个Body生成一个线程来读取数据库(如examples/mnist/mnist_train_lmdb)。QueuePair为前面两者之间的衔接、通信。
/** * @brief Reads data from a source to queues available to data layers. * A single reading thread is created per source, even if multiple solvers * are running in parallel, e.g. for multi-GPU training. This makes sure * databases are read sequentially, and that each solver accesses a different * subset of the database. Data is distributed to solvers in a round-robin * way to keep parallel training deterministic. */ class DataReader { public: ... protected: // Queue pairs are shared between a body and its readers class QueuePair { public: explicit QueuePair(int size); ~QueuePair(); BlockingQueue<Datum*> free_; BlockingQueue<Datum*> full_; }; // A single body is created per source class Body : public InternalThread { public: ... protected: void InternalThreadEntry(); void read_one(db::Cursor* cursor, QueuePair* qp); const LayerParameter param_; BlockingQueue<shared_ptr<QueuePair> > new_queue_pairs_; ... }; ... const shared_ptr<QueuePair> queue_pair_; shared_ptr<Body> body_; static map<const string, boost::weak_ptr<DataReader::Body> > bodies_; };
DataReader::QueuePair::QueuePair(int size) { // Initialize the free queue with requested number of datums for (int i = 0; i < size; ++i) { free_.push(new Datum()); } }
DataReader::Body::Body(const LayerParameter& param) : param_(param), new_queue_pairs_() { StartInternalThread(); }
说明:
DataReader类的构造函数如下:
map<const string, weak_ptr<DataReader::Body> > DataReader::bodies_; static boost::mutex bodies_mutex_; DataReader::DataReader(const LayerParameter& param) : queue_pair_(new QueuePair( // param.data_param().prefetch() * param.data_param().batch_size())) { // Get or create a body boost::mutex::scoped_lock lock(bodies_mutex_); string key = source_key(param); weak_ptr<Body>& weak = bodies_[key]; body_ = weak.lock(); if (!body_) { body_.reset(new Body(param)); bodies_[key] = weak_ptr<Body>(body_); } body_->new_queue_pairs_.push(queue_pair_); }说明:
void DataReader::Body::InternalThreadEntry() { ... vector<shared_ptr<QueuePair> > qps; try { ... // To ensure deterministic runs, only start running once all solvers // are ready. But solvers need to peek on one item during initialization, // so read one item, then wait for the next solver. for (int i = 0; i < solver_count; ++i) { shared_ptr<QueuePair> qp(new_queue_pairs_.pop()); read_one(cursor.get(), qp.get()); qps.push_back(qp); } // Main loop while (!must_stop()) { for (int i = 0; i < solver_count; ++i) { read_one(cursor.get(), qps[i].get()); } ... } } catch (boost::thread_interrupted&) { // Interrupted exception is expected on shutdown } }说明: