1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#ifndef QTHREAD_H
42#define QTHREAD_H
43
44#include <QtCore/qobject.h>
45#include <QtCore/qdeadlinetimer.h>
46
47// For QThread::create. The configure-time test just checks for the availability
48// of std::future and std::async; for the C++17 codepath we perform some extra
49// checks here (for std::invoke and C++14 lambdas).
50#if QT_CONFIG(cxx11_future)
51# include <future> // for std::async
52# include <functional> // for std::invoke; no guard needed as it's a C++98 header
53
54# if defined(__cpp_lib_invoke) && __cpp_lib_invoke >= 201411 \
55 && defined(__cpp_init_captures) && __cpp_init_captures >= 201304 \
56 && defined(__cpp_generic_lambdas) && __cpp_generic_lambdas >= 201304
57# define QTHREAD_HAS_VARIADIC_CREATE
58# endif
59#endif
60
61QT_BEGIN_NAMESPACE
62
63
64class QThreadData;
65class QThreadPrivate;
66class QAbstractEventDispatcher;
67
68class Q_CORE_EXPORT QThread : public QObject
69{
70 Q_OBJECT
71public:
72 static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION;
73 static QThread *currentThread();
74 static int idealThreadCount() noexcept;
75 static void yieldCurrentThread();
76
77 explicit QThread(QObject *parent = nullptr);
78 ~QThread();
79
80 enum Priority {
81 IdlePriority,
82
83 LowestPriority,
84 LowPriority,
85 NormalPriority,
86 HighPriority,
87 HighestPriority,
88
89 TimeCriticalPriority,
90
91 InheritPriority
92 };
93
94 void setPriority(Priority priority);
95 Priority priority() const;
96
97 bool isFinished() const;
98 bool isRunning() const;
99
100 void requestInterruption();
101 bool isInterruptionRequested() const;
102
103 void setStackSize(uint stackSize);
104 uint stackSize() const;
105
106 void exit(int retcode = 0);
107
108 QAbstractEventDispatcher *eventDispatcher() const;
109 void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher);
110
111 bool event(QEvent *event) override;
112 int loopLevel() const;
113
114#ifdef Q_CLANG_QDOC
115 template <typename Function, typename... Args>
116 static QThread *create(Function &&f, Args &&... args);
117 template <typename Function>
118 static QThread *create(Function &&f);
119#else
120# if QT_CONFIG(cxx11_future)
121# ifdef QTHREAD_HAS_VARIADIC_CREATE
122 template <typename Function, typename... Args>
123 static QThread *create(Function &&f, Args &&... args);
124# else
125 template <typename Function>
126 static QThread *create(Function &&f);
127# endif // QTHREAD_HAS_VARIADIC_CREATE
128# endif // QT_CONFIG(cxx11_future)
129#endif // Q_CLANG_QDOC
130
131public Q_SLOTS:
132 void start(Priority = InheritPriority);
133 void terminate();
134 void quit();
135
136public:
137 bool wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever));
138 // ### Qt6 inline this function
139 bool wait(unsigned long time);
140
141 static void sleep(unsigned long);
142 static void msleep(unsigned long);
143 static void usleep(unsigned long);
144
145Q_SIGNALS:
146 void started(QPrivateSignal);
147 void finished(QPrivateSignal);
148
149protected:
150 virtual void run();
151 int exec();
152
153 static void setTerminationEnabled(bool enabled = true);
154
155protected:
156 QThread(QThreadPrivate &dd, QObject *parent = nullptr);
157
158private:
159 Q_DECLARE_PRIVATE(QThread)
160
161#if QT_CONFIG(cxx11_future)
162 static QThread *createThreadImpl(std::future<void> &&future);
163#endif
164
165 friend class QCoreApplication;
166 friend class QThreadData;
167};
168
169#if QT_CONFIG(cxx11_future)
170
171#if defined(QTHREAD_HAS_VARIADIC_CREATE) || defined(Q_CLANG_QDOC)
172// C++17: std::thread's constructor complying call
173template <typename Function, typename... Args>
174QThread *QThread::create(Function &&f, Args &&... args)
175{
176 using DecayedFunction = typename std::decay<Function>::type;
177 auto threadFunction =
178 [f = static_cast<DecayedFunction>(std::forward<Function>(f))](auto &&... largs) mutable -> void
179 {
180 (void)std::invoke(std::move(f), std::forward<decltype(largs)>(largs)...);
181 };
182
183 return createThreadImpl(std::async(std::launch::deferred,
184 std::move(threadFunction),
185 std::forward<Args>(args)...));
186}
187#elif defined(__cpp_init_captures) && __cpp_init_captures >= 201304
188// C++14: implementation for just one callable
189template <typename Function>
190QThread *QThread::create(Function &&f)
191{
192 using DecayedFunction = typename std::decay<Function>::type;
193 auto threadFunction =
194 [f = static_cast<DecayedFunction>(std::forward<Function>(f))]() mutable -> void
195 {
196 (void)f();
197 };
198
199 return createThreadImpl(std::async(std::launch::deferred, std::move(threadFunction)));
200}
201#else
202// C++11: same as C++14, but with a workaround for not having generalized lambda captures
203namespace QtPrivate {
204template <typename Function>
205struct Callable
206{
207 explicit Callable(Function &&f)
208 : m_function(std::forward<Function>(f))
209 {
210 }
211
212 // Apply the same semantics of a lambda closure type w.r.t. the special
213 // member functions, if possible: delete the copy assignment operator,
214 // bring back all the others as per the RO5 (cf. §8.1.5.1/11 [expr.prim.lambda.closure])
215 ~Callable() = default;
216 Callable(const Callable &) = default;
217 Callable(Callable &&) = default;
218 Callable &operator=(const Callable &) = delete;
219 Callable &operator=(Callable &&) = default;
220
221 void operator()()
222 {
223 (void)m_function();
224 }
225
226 typename std::decay<Function>::type m_function;
227};
228} // namespace QtPrivate
229
230template <typename Function>
231QThread *QThread::create(Function &&f)
232{
233 return createThreadImpl(std::async(std::launch::deferred, QtPrivate::Callable<Function>(std::forward<Function>(f))));
234}
235#endif // QTHREAD_HAS_VARIADIC_CREATE
236
237#endif // QT_CONFIG(cxx11_future)
238
239QT_END_NAMESPACE
240
241#endif // QTHREAD_H
242