PRCYCoin  2.0.0.7rc1
P2P Digital Currency
checkqueue.h
Go to the documentation of this file.
1 // Copyright (c) 2012-2014 The Bitcoin developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #ifndef BITCOIN_CHECKQUEUE_H
6 #define BITCOIN_CHECKQUEUE_H
7 
8 #include <algorithm>
9 #include <vector>
10 
11 #include <boost/thread/condition_variable.hpp>
12 #include <boost/thread/locks.hpp>
13 #include <boost/thread/mutex.hpp>
14 
15 template <typename T>
17 
28 template <typename T>
30 {
31 private:
33  boost::mutex mutex;
34 
36  boost::condition_variable condWorker;
37 
39  boost::condition_variable condMaster;
40 
43  std::vector<T> queue;
44 
46  int nIdle;
47 
49  int nTotal;
50 
52  bool fAllOk;
53 
59  unsigned int nTodo;
60 
62  bool fQuit;
63 
65  unsigned int nBatchSize;
66 
68  bool Loop(bool fMaster = false)
69  {
70  boost::condition_variable& cond = fMaster ? condMaster : condWorker;
71  std::vector<T> vChecks;
72  vChecks.reserve(nBatchSize);
73  unsigned int nNow = 0;
74  bool fOk = true;
75  do {
76  {
77  boost::unique_lock<boost::mutex> lock(mutex);
78  // first do the clean-up of the previous loop run (allowing us to do it in the same critsect)
79  if (nNow) {
80  fAllOk &= fOk;
81  nTodo -= nNow;
82  if (nTodo == 0 && !fMaster)
83  // We processed the last element; inform the master he can exit and return the result
84  condMaster.notify_one();
85  } else {
86  // first iteration
87  nTotal++;
88  }
89  // logically, the do loop starts here
90  while (queue.empty()) {
91  if ((fMaster || fQuit) && nTodo == 0) {
92  nTotal--;
93  bool fRet = fAllOk;
94  // reset the status for new work later
95  if (fMaster)
96  fAllOk = true;
97  // return the current status
98  return fRet;
99  }
100  nIdle++;
101  cond.wait(lock); // wait
102  nIdle--;
103  }
104  // Decide how many work units to process now.
105  // * Do not try to do everything at once, but aim for increasingly smaller batches so
106  // all workers finish approximately simultaneously.
107  // * Try to account for idle jobs which will instantly start helping.
108  // * Don't do batches smaller than 1 (duh), or larger than nBatchSize.
109  nNow = std::max(1U, std::min(nBatchSize, (unsigned int)queue.size() / (nTotal + nIdle + 1)));
110  vChecks.resize(nNow);
111  for (unsigned int i = 0; i < nNow; i++) {
112  // We want the lock on the mutex to be as short as possible, so swap jobs from the global
113  // queue to the local batch vector instead of copying.
114  vChecks[i].swap(queue.back());
115  queue.pop_back();
116  }
117  // Check whether we need to do work at all
118  fOk = fAllOk;
119  }
120  // execute work
121  for (T& check : vChecks)
122  if (fOk)
123  fOk = check();
124  vChecks.clear();
125  } while (true);
126  }
127 
128 public:
130  CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {}
131 
133  void Thread()
134  {
135  Loop();
136  }
137 
139  bool Wait()
140  {
141  return Loop(true);
142  }
143 
145  void Add(std::vector<T>& vChecks)
146  {
147  boost::unique_lock<boost::mutex> lock(mutex);
148  for (T& check : vChecks) {
149  queue.push_back(T());
150  check.swap(queue.back());
151  }
152  nTodo += vChecks.size();
153  if (vChecks.size() == 1)
154  condWorker.notify_one();
155  else if (vChecks.size() > 1)
156  condWorker.notify_all();
157  }
158 
160  {
161  }
162 
163  bool IsIdle()
164  {
165  boost::unique_lock<boost::mutex> lock(mutex);
166  return (nTotal == nIdle && nTodo == 0 && fAllOk == true);
167  }
168 };
169 
174 template <typename T>
175 class CCheckQueueControl
176 {
177 private:
179  bool fDone;
180 
181 public:
182  CCheckQueueControl(CCheckQueue<T>* pqueueIn) : pqueue(pqueueIn), fDone(false)
183  {
184  // passed queue is supposed to be unused, or NULL
185  if (pqueue != NULL) {
186  bool isIdle = pqueue->IsIdle();
187  assert(isIdle);
188  }
189  }
190 
191  bool Wait()
192  {
193  if (pqueue == NULL)
194  return true;
195  bool fRet = pqueue->Wait();
196  fDone = true;
197  return fRet;
198  }
199 
200  void Add(std::vector<T>& vChecks)
201  {
202  if (pqueue != NULL)
203  pqueue->Add(vChecks);
204  }
205 
207  {
208  if (!fDone)
209  Wait();
210  }
211 };
212 
213 #endif // BITCOIN_CHECKQUEUE_H
CCheckQueue::Loop
bool Loop(bool fMaster=false)
Internal function that does bulk of the verification work.
Definition: checkqueue.h:68
CCheckQueue::nTodo
unsigned int nTodo
Number of verifications that haven't completed yet.
Definition: checkqueue.h:59
CCheckQueue::~CCheckQueue
~CCheckQueue()
Definition: checkqueue.h:159
CCheckQueueControl::pqueue
CCheckQueue< T > * pqueue
Definition: checkqueue.h:178
CCheckQueue::Thread
void Thread()
Worker thread.
Definition: checkqueue.h:133
CCheckQueue::CCheckQueue
CCheckQueue(unsigned int nBatchSizeIn)
Create a new check queue.
Definition: checkqueue.h:130
CCheckQueue::queue
std::vector< T > queue
The queue of elements to be processed.
Definition: checkqueue.h:43
CCheckQueue::fAllOk
bool fAllOk
The temporary evaluation result.
Definition: checkqueue.h:52
CCheckQueue::condWorker
boost::condition_variable condWorker
Worker threads block on this when out of work.
Definition: checkqueue.h:36
CCheckQueueControl::Add
void Add(std::vector< T > &vChecks)
Definition: checkqueue.h:200
CCheckQueue::fQuit
bool fQuit
Whether we're shutting down.
Definition: checkqueue.h:62
CCheckQueue
Queue for verifications that have to be performed.
Definition: checkqueue.h:29
CCheckQueue::mutex
boost::mutex mutex
Mutex to protect the inner state.
Definition: checkqueue.h:33
CCheckQueueControl
RAII-style controller object for a CCheckQueue that guarantees the passed queue is finished before co...
Definition: checkqueue.h:16
CCheckQueue::IsIdle
bool IsIdle()
Definition: checkqueue.h:163
CCheckQueue::nTotal
int nTotal
The total number of workers (including the master).
Definition: checkqueue.h:49
CCheckQueueControl::CCheckQueueControl
CCheckQueueControl(CCheckQueue< T > *pqueueIn)
Definition: checkqueue.h:182
CCheckQueueControl::Wait
bool Wait()
Definition: checkqueue.h:191
CCheckQueue::nBatchSize
unsigned int nBatchSize
The maximum number of elements to be processed in one batch.
Definition: checkqueue.h:65
CCheckQueueControl::fDone
bool fDone
Definition: checkqueue.h:179
CCheckQueue::Add
void Add(std::vector< T > &vChecks)
Add a batch of checks to the queue.
Definition: checkqueue.h:145
CCheckQueue::nIdle
int nIdle
The number of workers (including the master) that are idle.
Definition: checkqueue.h:46
CCheckQueueControl::~CCheckQueueControl
~CCheckQueueControl()
Definition: checkqueue.h:206
CCheckQueue::condMaster
boost::condition_variable condMaster
Master thread blocks on this when out of work.
Definition: checkqueue.h:39
CCheckQueue::Wait
bool Wait()
Wait until execution finishes, and return whether all evaluations where successful.
Definition: checkqueue.h:139