1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QTHREADPOOL_P_H
5#define QTHREADPOOL_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17//
18
19#include "QtCore/qmutex.h"
20#include "QtCore/qthread.h"
21#include "QtCore/qwaitcondition.h"
22#include "QtCore/qthreadpool.h"
23#include "QtCore/qset.h"
24#include "QtCore/qqueue.h"
25#include "private/qobject_p.h"
26
27QT_REQUIRE_CONFIG(thread);
28
29QT_BEGIN_NAMESPACE
30
31class QDeadlineTimer;
32
33class QueuePage
34{
35public:
36 enum {
37 MaxPageSize = 256
38 };
39
40 QueuePage(QRunnable *runnable, int pri) : m_priority(pri) { push(runnable); }
41
42 bool isFull() { return m_lastIndex >= MaxPageSize - 1; }
43
44 bool isFinished() { return m_firstIndex > m_lastIndex; }
45
46 void push(QRunnable *runnable)
47 {
48 Q_ASSERT(runnable != nullptr);
49 Q_ASSERT(!isFull());
50 m_lastIndex += 1;
51 m_entries[m_lastIndex] = runnable;
52 }
53
54 void skipToNextOrEnd()
55 {
56 while (!isFinished() && m_entries[m_firstIndex] == nullptr) {
57 m_firstIndex += 1;
58 }
59 }
60
61 QRunnable *first()
62 {
63 Q_ASSERT(!isFinished());
64 QRunnable *runnable = m_entries[m_firstIndex];
65 Q_ASSERT(runnable);
66 return runnable;
67 }
68
69 QRunnable *pop()
70 {
71 Q_ASSERT(!isFinished());
72 QRunnable *runnable = first();
73 Q_ASSERT(runnable);
74
75 // clear the entry although this should not be necessary
76 m_entries[m_firstIndex] = nullptr;
77 m_firstIndex += 1;
78
79 // make sure the next runnable returned by first() is not a nullptr
80 skipToNextOrEnd();
81
82 return runnable;
83 }
84
85 bool tryTake(QRunnable *runnable)
86 {
87 Q_ASSERT(!isFinished());
88 for (int i = m_firstIndex; i <= m_lastIndex; i++) {
89 if (m_entries[i] == runnable) {
90 m_entries[i] = nullptr;
91 if (i == m_firstIndex) {
92 // make sure first() does not return a nullptr
93 skipToNextOrEnd();
94 }
95 return true;
96 }
97 }
98 return false;
99 }
100
101 int priority() const { return m_priority; }
102
103private:
104 int m_priority = 0;
105 int m_firstIndex = 0;
106 int m_lastIndex = -1;
107 QRunnable *m_entries[MaxPageSize];
108};
109
110class QThreadPoolThread;
111class Q_CORE_EXPORT QThreadPoolPrivate : public QObjectPrivate
112{
113 Q_DECLARE_PUBLIC(QThreadPool)
114 friend class QThreadPoolThread;
115
116public:
117 QThreadPoolPrivate();
118
119 bool tryStart(QRunnable *task);
120 void enqueueTask(QRunnable *task, int priority = 0);
121 int activeThreadCount() const;
122
123 void tryToStartMoreThreads();
124 bool areAllThreadsActive() const;
125 bool tooManyThreadsActive() const;
126
127 int maxThreadCount() const
128 { return qMax(a: requestedMaxThreadCount, b: 1); } // documentation says we start at least one
129 void startThread(QRunnable *runnable = nullptr);
130 void reset();
131 bool waitForDone(int msecs);
132 bool waitForDone(const QDeadlineTimer &timer);
133 void clear();
134 void stealAndRunRunnable(QRunnable *runnable);
135 void deletePageIfFinished(QueuePage *page);
136
137 static QThreadPool *qtGuiInstance();
138
139 mutable QMutex mutex;
140 QSet<QThreadPoolThread *> allThreads;
141 QQueue<QThreadPoolThread *> waitingThreads;
142 QQueue<QThreadPoolThread *> expiredThreads;
143 QList<QueuePage *> queue;
144 QWaitCondition noActiveThreads;
145 QString objectName;
146
147 int expiryTimeout = 30000;
148 int requestedMaxThreadCount = QThread::idealThreadCount(); // don't use this directly
149 int reservedThreads = 0;
150 int activeThreads = 0;
151 uint stackSize = 0;
152 QThread::Priority threadPriority = QThread::InheritPriority;
153};
154
155QT_END_NAMESPACE
156
157#endif
158

source code of qtbase/src/corelib/thread/qthreadpool_p.h