Changeset 57631 in vbox for trunk/src/VBox/Frontends
- Timestamp:
- Sep 4, 2015 1:55:49 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/src/globals/UIThreadPool.cpp
r57629 r57631 33 33 #endif /* !VBOX_WITH_PRECOMPILED_HEADERS */ 34 34 35 36 35 /** QThread extension used as worker-thread. 37 36 * Capable of executing COM-related tasks. */ … … 52 51 53 52 /** Returns worker-thread index within the worker-thread pool registry. */ 54 int getIndex() const { return m_iIndex; }53 int index() const { return m_iIndex; } 55 54 56 55 /** Disables sigFinished signal, for optimizing worker-thread pool termination. */ 57 void setNoFinishedSignal() 58 { 59 m_fNoFinishedSignal = true; 60 } 56 void setNoFinishedSignal() { m_fNoFinishedSignal = true; } 61 57 62 58 private: … … 74 70 bool m_fNoFinishedSignal; 75 71 }; 76 77 72 78 73 UIThreadPool::UIThreadPool(ulong cMaxWorkers /* = 3 */, ulong cMsWorkerIdleTimeout /* = 5000 */) … … 81 76 , m_cWorkers(0) 82 77 , m_cIdleWorkers(0) 83 , m_fTerminating(false) /* termination status */78 , m_fTerminating(false) 84 79 { 85 80 } … … 87 82 UIThreadPool::~UIThreadPool() 88 83 { 89 /* Set termination status and alert all idle worker threads: */84 /* Set termination status: */ 90 85 setTerminating(); 91 86 92 m_everythingLocker.lock(); /* paranoia */ 87 /* Lock initially: */ 88 m_everythingLocker.lock(); 93 89 94 90 /* Cleanup all the workers: */ 95 91 for (int idxWorker = 0; idxWorker < m_workers.size(); ++idxWorker) 96 92 { 97 UIThreadWorker *pWorker = m_workers[idxWorker]; 98 m_workers[idxWorker] = NULL; 99 100 /* Clean up the worker, if there was one. */ 93 /* Acquire the worker: */ 94 UIThreadWorker *pWorker = m_workers.at(idxWorker); 95 /* Remove it from the registry: */ 96 m_workers[idxWorker] = 0; 97 98 /* Clean up the worker, if there was one: */ 101 99 if (pWorker) 102 100 { 103 m_cWorkers--; 101 /* Decrease the number of workers: */ 102 --m_cWorkers; 103 /* Unlock temporary to let the worker finish: */ 104 104 m_everythingLocker.unlock(); 105 105 /* Wait for the worker to finish: */ 106 106 pWorker->wait(); 107 107 /* Lock again: */ 108 108 m_everythingLocker.lock(); 109 /* Delete the worker finally: */ 109 110 delete pWorker; 110 111 } 111 112 } 112 113 114 /* Unlock finally: */ 113 115 m_everythingLocker.unlock(); 114 116 } … … 116 118 bool UIThreadPool::isTerminating() const 117 119 { 120 /* Lock initially: */ 121 m_everythingLocker.lock(); 122 118 123 /* Acquire termination-flag: */ 119 m_everythingLocker.lock();120 124 bool fTerminating = m_fTerminating; 121 m_everythingLocker.unlock(); 122 125 126 /* Unlock finally: */ 127 m_everythingLocker.unlock(); 128 129 /* Return termination-flag: */ 123 130 return fTerminating; 124 131 } … … 126 133 void UIThreadPool::setTerminating() 127 134 { 128 m_everythingLocker.lock(); 129 130 /* Indicate that we're terminating: */ 135 /* Lock initially: */ 136 m_everythingLocker.lock(); 137 138 /* Assign termination-flag: */ 131 139 m_fTerminating = true; 132 140 … … 134 142 for (int idxWorker = 0; idxWorker < m_workers.size(); ++idxWorker) 135 143 { 136 UIThreadWorker *pWorker = m_workers [idxWorker];144 UIThreadWorker *pWorker = m_workers.at(idxWorker); 137 145 if (pWorker) 138 146 pWorker->setNoFinishedSignal(); … … 142 150 m_taskCondition.wakeAll(); 143 151 152 /* Unlock finally: */ 144 153 m_everythingLocker.unlock(); 145 154 } … … 147 156 void UIThreadPool::enqueueTask(UITask *pTask) 148 157 { 149 Assert(!isTerminating()); 158 /* Do nothing if terminating: */ 159 AssertReturnVoid(!isTerminating()); 150 160 151 161 /* Prepare task: */ 152 connect(pTask, SIGNAL(sigComplete(UITask*)), this, SLOT(sltHandleTaskComplete(UITask*)), Qt::QueuedConnection); 153 154 m_everythingLocker.lock(); 155 156 /* Put the task onto the queue: */ 162 connect(pTask, SIGNAL(sigComplete(UITask*)), 163 this, SLOT(sltHandleTaskComplete(UITask*)), Qt::QueuedConnection); 164 165 /* Lock initially: */ 166 m_everythingLocker.lock(); 167 168 /* Put the task into the queue: */ 157 169 m_tasks.enqueue(pTask); 158 170 … … 168 180 int idxFirstUnused = m_workers.size(); 169 181 while (idxFirstUnused-- > 0) 170 if (m_workers [idxFirstUnused] == NULL)182 if (m_workers.at(idxFirstUnused) == 0) 171 183 { 172 184 /* Prepare the new worker: */ 173 185 UIThreadWorker *pWorker = new UIThreadWorker(this, idxFirstUnused); 174 connect(pWorker, SIGNAL(sigFinished(UIThreadWorker*)), this,175 SLOT(sltHandleWorkerFinished(UIThreadWorker*)), Qt::QueuedConnection);186 connect(pWorker, SIGNAL(sigFinished(UIThreadWorker*)), 187 this, SLOT(sltHandleWorkerFinished(UIThreadWorker*)), Qt::QueuedConnection); 176 188 m_workers[idxFirstUnused] = pWorker; 177 m_cWorkers++;189 ++m_cWorkers; 178 190 179 191 /* And start it: */ … … 182 194 } 183 195 } 184 /* else: wait for some worker to complete whatever it's busy with and jump to it. */ 185 196 /* else: wait for some worker to complete 197 * whatever it's busy with and jump to it. */ 198 199 /* Unlock finally: */ 186 200 m_everythingLocker.unlock(); 187 201 } … … 189 203 UITask* UIThreadPool::dequeueTask(UIThreadWorker *pWorker) 190 204 { 205 /* Lock initially: */ 206 m_everythingLocker.lock(); 207 191 208 /* Dequeue a task, watching out for terminations. 192 * For opimal efficiency in enqueueTask() we keep count of idle threads. 193 * If the wait times out, we'll return NULL and terminate the thread. */ 194 m_everythingLocker.lock(); 195 209 * For optimal efficiency in enqueueTask() we keep count of idle threads. 210 * If the wait times out, we'll return 0 and terminate the thread. */ 196 211 bool fIdleTimedOut = false; 197 212 while (!m_fTerminating) 198 213 { 199 Assert(m_workers[pWorker->getIndex()] == pWorker); /* paranoia */ 214 /* Make sure that worker has proper index: */ 215 Assert(m_workers.at(pWorker->index()) == pWorker); 200 216 201 217 /* Dequeue task if there is one: */ … … 205 221 if (pTask) 206 222 { 223 /* Unlock finally: */ 207 224 m_everythingLocker.unlock(); 225 226 /* Return dequeued task: */ 208 227 return pTask; 209 228 } … … 211 230 212 231 /* If we timed out already, then quit the worker thread. To prevent a 213 214 215 232 * race between enqueueTask and the queue removal of the thread from 233 * the workers vector, we remove it here already. (This does not apply 234 * to the termination scenario.) */ 216 235 if (fIdleTimedOut) 217 236 { 218 m_workers[pWorker-> getIndex()] = NULL;219 m_cWorkers--;237 m_workers[pWorker->index()] = 0; 238 --m_cWorkers; 220 239 break; 221 240 } 222 241 223 /* Wait for a task or timeout .*/224 m_cIdleWorkers++;242 /* Wait for a task or timeout: */ 243 ++m_cIdleWorkers; 225 244 fIdleTimedOut = !m_taskCondition.wait(&m_everythingLocker, m_cMsIdleTimeout); 226 m_cIdleWorkers--; 227 } 228 229 m_everythingLocker.unlock(); 230 231 return NULL; 245 --m_cIdleWorkers; 246 } 247 248 /* Unlock finally: */ 249 m_everythingLocker.unlock(); 250 251 /* Return 0 by default: */ 252 return 0; 232 253 } 233 254 … … 245 266 { 246 267 /* Wait for the thread to finish completely, then delete the thread 247 248 268 * object. We have already removed the thread from the workers vector. 269 * Note! We don't want to use 'this' here, in case it's invalid. */ 249 270 pWorker->wait(); 250 271 delete pWorker; 251 272 } 252 273 253 254 274 UITask::UITask(const QVariant &data) 255 275 : m_data(data) … … 261 281 /* Run task: */ 262 282 run(); 263 /* Notify listener : */283 /* Notify listeners: */ 264 284 emit sigComplete(this); 265 285 } 266 267 286 268 287 UIThreadWorker::UIThreadWorker(UIThreadPool *pPool, int iIndex) … … 278 297 COMBase::InitializeCOM(false); 279 298 280 /* Try get a task from the pool queue .*/299 /* Try get a task from the pool queue: */ 281 300 while (UITask *pTask = m_pPool->dequeueTask(this)) 282 301 { … … 290 309 COMBase::CleanupCOM(); 291 310 292 /* Queue a signal tofor the pool to do thread cleanup, unless the pool is311 /* Queue a signal for the pool to do thread cleanup, unless the pool is 293 312 already terminating and doesn't need the signal. */ 294 313 if (!m_fNoFinishedSignal) … … 296 315 } 297 316 298 299 317 #include "UIThreadPool.moc" 300 318
Note:
See TracChangeset
for help on using the changeset viewer.