1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of the QtCore module of the Qt Toolkit. 7 ** 8 ** $QT_BEGIN_LICENSE:LGPL$ 9 ** Commercial License Usage 10 ** Licensees holding valid commercial Qt licenses may use this file in 11 ** accordance with the commercial license agreement provided with the 12 ** Software or, alternatively, in accordance with the terms contained in 13 ** a written agreement between you and The Qt Company. For licensing terms 14 ** and conditions see https://www.qt.io/terms-conditions. For further 15 ** information use the contact form at https://www.qt.io/contact-us. 16 ** 17 ** GNU Lesser General Public License Usage 18 ** Alternatively, this file may be used under the terms of the GNU Lesser 19 ** General Public License version 3 as published by the Free Software 20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 21 ** packaging of this file. Please review the following information to 22 ** ensure the GNU Lesser General Public License version 3 requirements 23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24 ** 25 ** GNU General Public License Usage 26 ** Alternatively, this file may be used under the terms of the GNU 27 ** General Public License version 2.0 or (at your option) the GNU General 28 ** Public license version 3 or any later version approved by the KDE Free 29 ** Qt Foundation. The licenses are as published by the Free Software 30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31 ** included in the packaging of this file. Please review the following 32 ** information to ensure the GNU General Public License requirements will 33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34 ** https://www.gnu.org/licenses/gpl-3.0.html. 35 ** 36 ** $QT_END_LICENSE$ 37 ** 38 ****************************************************************************/ 39 40 #ifndef QTHREADPOOL_P_H 41 #define QTHREADPOOL_P_H 42 43 // 44 // W A R N I N G 45 // ------------- 46 // 47 // This file is not part of the Qt API. It exists purely as an 48 // implementation detail. This header file may change from version to 49 // version without notice, or even be removed. 50 // 51 // We mean it. 52 // 53 // 54 55 #include "QtCore/qmutex.h" 56 #include "QtCore/qthread.h" 57 #include "QtCore/qwaitcondition.h" 58 #include "QtCore/qset.h" 59 #include "QtCore/qqueue.h" 60 #include "private/qobject_p.h" 61 62 QT_REQUIRE_CONFIG(thread); 63 64 QT_BEGIN_NAMESPACE 65 66 class QDeadlineTimer; 67 68 class QueuePage { 69 public: 70 enum { 71 MaxPageSize = 256 72 }; 73 QueuePage(QRunnable * runnable,int pri)74 QueuePage(QRunnable *runnable, int pri) 75 : m_priority(pri) 76 { 77 push(runnable); 78 } 79 isFull()80 bool isFull() { 81 return m_lastIndex >= MaxPageSize - 1; 82 } 83 isFinished()84 bool isFinished() { 85 return m_firstIndex > m_lastIndex; 86 } 87 push(QRunnable * runnable)88 void push(QRunnable *runnable) { 89 Q_ASSERT(runnable != nullptr); 90 Q_ASSERT(!isFull()); 91 m_lastIndex += 1; 92 m_entries[m_lastIndex] = runnable; 93 } 94 skipToNextOrEnd()95 void skipToNextOrEnd() { 96 while (!isFinished() && m_entries[m_firstIndex] == nullptr) { 97 m_firstIndex += 1; 98 } 99 } 100 first()101 QRunnable *first() { 102 Q_ASSERT(!isFinished()); 103 QRunnable *runnable = m_entries[m_firstIndex]; 104 Q_ASSERT(runnable); 105 return runnable; 106 } 107 pop()108 QRunnable *pop() { 109 Q_ASSERT(!isFinished()); 110 QRunnable *runnable = first(); 111 Q_ASSERT(runnable); 112 113 // clear the entry although this should not be necessary 114 m_entries[m_firstIndex] = nullptr; 115 m_firstIndex += 1; 116 117 // make sure the next runnable returned by first() is not a nullptr 118 skipToNextOrEnd(); 119 120 return runnable; 121 } 122 tryTake(QRunnable * runnable)123 bool tryTake(QRunnable *runnable) { 124 Q_ASSERT(!isFinished()); 125 for (int i = m_firstIndex; i <= m_lastIndex; i++) { 126 if (m_entries[i] == runnable) { 127 m_entries[i] = nullptr; 128 if (i == m_firstIndex) { 129 // make sure first() does not return a nullptr 130 skipToNextOrEnd(); 131 } 132 return true; 133 } 134 } 135 return false; 136 } 137 priority()138 int priority() const { 139 return m_priority; 140 } 141 142 private: 143 int m_priority = 0; 144 int m_firstIndex = 0; 145 int m_lastIndex = -1; 146 QRunnable *m_entries[MaxPageSize]; 147 }; 148 149 class QThreadPoolThread; 150 class Q_CORE_EXPORT QThreadPoolPrivate : public QObjectPrivate 151 { 152 Q_DECLARE_PUBLIC(QThreadPool) 153 friend class QThreadPoolThread; 154 155 public: 156 QThreadPoolPrivate(); 157 158 bool tryStart(QRunnable *task); 159 void enqueueTask(QRunnable *task, int priority = 0); 160 int activeThreadCount() const; 161 162 void tryToStartMoreThreads(); 163 bool tooManyThreadsActive() const; 164 165 void startThread(QRunnable *runnable = nullptr); 166 void reset(); 167 bool waitForDone(int msecs); 168 bool waitForDone(const QDeadlineTimer &timer); 169 void clear(); 170 void stealAndRunRunnable(QRunnable *runnable); 171 void deletePageIfFinished(QueuePage *page); 172 173 mutable QMutex mutex; 174 QSet<QThreadPoolThread *> allThreads; 175 QQueue<QThreadPoolThread *> waitingThreads; 176 QQueue<QThreadPoolThread *> expiredThreads; 177 QVector<QueuePage*> queue; 178 QWaitCondition noActiveThreads; 179 180 int expiryTimeout = 30000; 181 int maxThreadCount = QThread::idealThreadCount(); 182 int reservedThreads = 0; 183 int activeThreads = 0; 184 uint stackSize = 0; 185 }; 186 187 QT_END_NAMESPACE 188 189 #endif 190