// // Created by Bradley Austin Davis 2015/07/08. // Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #pragma once #ifndef hifi_GenericQueueThread_h #define hifi_GenericQueueThread_h #include #include #include #include #include #include "GenericThread.h" #include "NumericalConstants.h" template class GenericQueueThread : public GenericThread { public: using Queue = QQueue; GenericQueueThread(QObject* parent = nullptr) : GenericThread() {} virtual ~GenericQueueThread() {} void queueItem(const T& t) { lock(); queueItemInternal(t); unlock(); _hasItems.wakeAll(); } void waitIdle(uint32_t maxWaitMs = UINT32_MAX) { QElapsedTimer timer; timer.start(); // FIXME this will work as long as the thread doing the wait // is the only thread which can add work to the queue. // It would be better if instead we had a queue empty condition to wait on // that would ensure that we get woken as soon as we're idle the very // first time the queue was empty. while (timer.elapsed() < maxWaitMs) { lock(); if (!_items.size()) { unlock(); return; } unlock(); } } virtual bool process() override { lock(); if (!_items.size()) { unlock(); _hasItemsMutex.lock(); _hasItems.wait(&_hasItemsMutex, getMaxWait()); _hasItemsMutex.unlock(); } else { unlock(); } lock(); if (!_items.size()) { unlock(); return isStillRunning(); } Queue processItems; processItems.swap(_items); unlock(); return processQueueItems(processItems); } protected: virtual void queueItemInternal(const T& t) { _items.push_back(t); } virtual uint32_t getMaxWait() { return MSECS_PER_SECOND; } virtual bool processQueueItems(const Queue& items) = 0; Queue _items; QWaitCondition _hasItems; QMutex _hasItemsMutex; }; #endif // hifi_GenericQueueThread_h