diff options
Diffstat (limited to 'src/checkqueue.h')
| -rw-r--r-- | src/checkqueue.h | 129 |
1 files changed, 75 insertions, 54 deletions
diff --git a/src/checkqueue.h b/src/checkqueue.h index ef7b4ca42..20ba25bb4 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -1,9 +1,9 @@ -// Copyright (c) 2012 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Copyright (c) 2012-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef CHECKQUEUE_H -#define CHECKQUEUE_H +#ifndef BITCOIN_CHECKQUEUE_H +#define BITCOIN_CHECKQUEUE_H #include <algorithm> #include <vector> @@ -13,9 +13,11 @@ #include <boost/thread/locks.hpp> #include <boost/thread/mutex.hpp> -template<typename T> class CCheckQueueControl; +template <typename T> +class CCheckQueueControl; -/** Queue for verifications that have to be performed. +/** + * Queue for verifications that have to be performed. * The verifications are represented by a type T, which must provide an * operator(), returning a bool. * @@ -24,44 +26,49 @@ template<typename T> class CCheckQueueControl; * the master is done adding work, it temporarily joins the worker pool * as an N'th worker, until all jobs are done. */ -template<typename T> class CCheckQueue { +template <typename T> +class CCheckQueue +{ private: - // Mutex to protect the inner state + //! Mutex to protect the inner state boost::mutex mutex; - // Worker threads block on this when out of work + //! Worker threads block on this when out of work boost::condition_variable condWorker; - // Master thread blocks on this when out of work + //! Master thread blocks on this when out of work boost::condition_variable condMaster; - // The queue of elements to be processed. - // As the order of booleans doesn't matter, it is used as a LIFO (stack) + //! The queue of elements to be processed. + //! As the order of booleans doesn't matter, it is used as a LIFO (stack) std::vector<T> queue; - // The number of workers (including the master) that are idle. + //! The number of workers (including the master) that are idle. int nIdle; - // The total number of workers (including the master). + //! The total number of workers (including the master). int nTotal; - // The temporary evaluation result. + //! The temporary evaluation result. bool fAllOk; - // Number of verifications that haven't completed yet. - // This includes elements that are not anymore in queue, but still in - // worker's own batches. + /** + * Number of verifications that haven't completed yet. + * This includes elements that are no longer queued, but still in the + * worker's own batches. + */ unsigned int nTodo; - // Whether we're shutting down. + //! Whether we're shutting down. bool fQuit; - // The maximum number of elements to be processed in one batch + //! The maximum number of elements to be processed in one batch unsigned int nBatchSize; - // Internal function that does bulk of the verification work. - bool Loop(bool fMaster = false) { - boost::condition_variable &cond = fMaster ? condMaster : condWorker; + /** Internal function that does bulk of the verification work. */ + bool Loop(bool fMaster = false) + { + boost::condition_variable& cond = fMaster ? condMaster : condWorker; std::vector<T> vChecks; vChecks.reserve(nBatchSize); unsigned int nNow = 0; @@ -74,7 +81,7 @@ private: fAllOk &= fOk; nTodo -= nNow; if (nTodo == 0 && !fMaster) - // We processed the last element; inform the master he can exit and return the result + // We processed the last element; inform the master it can exit and return the result condMaster.notify_one(); } else { // first iteration @@ -103,41 +110,43 @@ private: nNow = std::max(1U, std::min(nBatchSize, (unsigned int)queue.size() / (nTotal + nIdle + 1))); vChecks.resize(nNow); for (unsigned int i = 0; i < nNow; i++) { - // We want the lock on the mutex to be as short as possible, so swap jobs from the global - // queue to the local batch vector instead of copying. - vChecks[i].swap(queue.back()); - queue.pop_back(); + // We want the lock on the mutex to be as short as possible, so swap jobs from the global + // queue to the local batch vector instead of copying. + vChecks[i].swap(queue.back()); + queue.pop_back(); } // Check whether we need to do work at all fOk = fAllOk; } // execute work - BOOST_FOREACH(T &check, vChecks) + BOOST_FOREACH (T& check, vChecks) if (fOk) fOk = check(); vChecks.clear(); - } while(true); + } while (true); } public: - // Create a new check queue - CCheckQueue(unsigned int nBatchSizeIn) : - nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {} + //! Create a new check queue + CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {} - // Worker thread - void Thread() { + //! Worker thread + void Thread() + { Loop(); } - // Wait until execution finishes, and return whether all evaluations where succesful. - bool Wait() { + //! Wait until execution finishes, and return whether all evaluations were successful. + bool Wait() + { return Loop(true); } - // Add a batch of checks to the queue - void Add(std::vector<T> &vChecks) { + //! Add a batch of checks to the queue + void Add(std::vector<T>& vChecks) + { boost::unique_lock<boost::mutex> lock(mutex); - BOOST_FOREACH(T &check, vChecks) { + BOOST_FOREACH (T& check, vChecks) { queue.push_back(T()); check.swap(queue.back()); } @@ -148,31 +157,41 @@ public: condWorker.notify_all(); } - ~CCheckQueue() { + ~CCheckQueue() + { + } + + bool IsIdle() + { + boost::unique_lock<boost::mutex> lock(mutex); + return (nTotal == nIdle && nTodo == 0 && fAllOk == true); } - friend class CCheckQueueControl<T>; }; -/** RAII-style controller object for a CCheckQueue that guarantees the passed - * queue is finished before continuing. +/** + * RAII-style controller object for a CCheckQueue that guarantees the passed + * queue is finished before continuing. */ -template<typename T> class CCheckQueueControl { +template <typename T> +class CCheckQueueControl +{ private: - CCheckQueue<T> *pqueue; + CCheckQueue<T>* pqueue; bool fDone; public: - CCheckQueueControl(CCheckQueue<T> *pqueueIn) : pqueue(pqueueIn), fDone(false) { + CCheckQueueControl(CCheckQueue<T>* pqueueIn) : pqueue(pqueueIn), fDone(false) + { // passed queue is supposed to be unused, or NULL if (pqueue != NULL) { - assert(pqueue->nTotal == pqueue->nIdle); - assert(pqueue->nTodo == 0); - assert(pqueue->fAllOk == true); + bool isIdle = pqueue->IsIdle(); + assert(isIdle); } } - bool Wait() { + bool Wait() + { if (pqueue == NULL) return true; bool fRet = pqueue->Wait(); @@ -180,15 +199,17 @@ public: return fRet; } - void Add(std::vector<T> &vChecks) { + void Add(std::vector<T>& vChecks) + { if (pqueue != NULL) pqueue->Add(vChecks); } - ~CCheckQueueControl() { + ~CCheckQueueControl() + { if (!fDone) Wait(); } }; -#endif +#endif // BITCOIN_CHECKQUEUE_H |