1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QTHREAD_H
6#define QTHREAD_H
7
8#include <QtCore/qobject.h>
9#include <QtCore/qdeadlinetimer.h>
10
11// For QThread::create
12#include <future> // for std::async
13#include <functional> // for std::invoke; no guard needed as it's a C++98 header
14// internal compiler error with mingw 8.1
15#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86)
16#include <intrin.h>
17#endif
18
19QT_BEGIN_NAMESPACE
20
21
22class QThreadData;
23class QThreadPrivate;
24class QAbstractEventDispatcher;
25class QEventLoopLocker;
26
27class Q_CORE_EXPORT QThread : public QObject
28{
29 Q_OBJECT
30public:
31 static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION;
32 static QThread *currentThread();
33 static bool isMainThread() noexcept;
34 static int idealThreadCount() noexcept;
35 static void yieldCurrentThread();
36
37 explicit QThread(QObject *parent = nullptr);
38 ~QThread();
39
40 enum Priority {
41 IdlePriority,
42
43 LowestPriority,
44 LowPriority,
45 NormalPriority,
46 HighPriority,
47 HighestPriority,
48
49 TimeCriticalPriority,
50
51 InheritPriority
52 };
53
54 void setPriority(Priority priority);
55 Priority priority() const;
56
57 bool isFinished() const;
58 bool isRunning() const;
59
60 void requestInterruption();
61 bool isInterruptionRequested() const;
62
63 void setStackSize(uint stackSize);
64 uint stackSize() const;
65
66 QAbstractEventDispatcher *eventDispatcher() const;
67 void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher);
68
69 bool event(QEvent *event) override;
70 int loopLevel() const;
71
72 bool isCurrentThread() const noexcept;
73
74 template <typename Function, typename... Args>
75 [[nodiscard]] static QThread *create(Function &&f, Args &&... args);
76
77public Q_SLOTS:
78 void start(Priority = InheritPriority);
79 void terminate();
80 void exit(int retcode = 0);
81 void quit();
82
83public:
84 bool wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever));
85 bool wait(unsigned long time)
86 {
87 if (time == (std::numeric_limits<unsigned long>::max)())
88 return wait(deadline: QDeadlineTimer(QDeadlineTimer::Forever));
89 return wait(deadline: QDeadlineTimer(time));
90 }
91
92 static void sleep(unsigned long);
93 static void msleep(unsigned long);
94 static void usleep(unsigned long);
95 static void sleep(std::chrono::nanoseconds nsec);
96
97Q_SIGNALS:
98 void started(QPrivateSignal);
99 void finished(QPrivateSignal);
100
101protected:
102 virtual void run();
103 int exec();
104
105 static void setTerminationEnabled(bool enabled = true);
106
107protected:
108 QThread(QThreadPrivate &dd, QObject *parent = nullptr);
109
110private:
111 Q_DECLARE_PRIVATE(QThread)
112 friend class QEventLoopLocker;
113
114 [[nodiscard]] static QThread *createThreadImpl(std::future<void> &&future);
115 static Qt::HANDLE currentThreadIdImpl() noexcept Q_DECL_PURE_FUNCTION;
116
117 friend class QCoreApplication;
118 friend class QThreadData;
119};
120
121template <typename Function, typename... Args>
122QThread *QThread::create(Function &&f, Args &&... args)
123{
124 using DecayedFunction = typename std::decay<Function>::type;
125 auto threadFunction =
126 [f = static_cast<DecayedFunction>(std::forward<Function>(f))](auto &&... largs) mutable -> void
127 {
128 (void)std::invoke(std::move(f), std::forward<decltype(largs)>(largs)...);
129 };
130
131 return createThreadImpl(future: std::async(std::launch::deferred,
132 std::move(threadFunction),
133 std::forward<Args>(args)...));
134}
135
136/*
137 On architectures and platforms we know, interpret the thread control
138 block (TCB) as a unique identifier for a thread within a process. Otherwise,
139 fall back to a slower but safe implementation.
140
141 As per the documentation of currentThreadId, we return an opaque handle
142 as a thread identifier, and application code is not supposed to use that
143 value for anything. In Qt we use the handle to check if threads are identical,
144 for which the TCB is sufficient.
145
146 So we use the fastest possible way, rather than spend time on returning
147 some pseudo-interoperable value.
148*/
149inline Qt::HANDLE QThread::currentThreadId() noexcept
150{
151 // define is undefed if we have to fall back to currentThreadIdImpl
152#define QT_HAS_FAST_CURRENT_THREAD_ID
153 Qt::HANDLE tid; // typedef to void*
154 static_assert(sizeof(tid) == sizeof(void*));
155 // See https://akkadia.org/drepper/tls.pdf for x86 ABI
156#if defined(Q_PROCESSOR_X86_32) && ((defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD)) // x86 32-bit always uses GS
157 __asm__("mov %%gs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : );
158#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_DARWIN)
159 // 64bit macOS uses GS, see https://github.com/apple/darwin-xnu/blob/master/libsyscall/os/tsd.h
160 __asm__("mov %%gs:0, %0" : "=r" (tid) : : );
161#elif defined(Q_PROCESSOR_X86_64) && ((defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD))
162 // x86_64 Linux, BSD uses FS
163 __asm__("mov %%fs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : );
164#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_WIN)
165 // See https://en.wikipedia.org/wiki/Win32_Thread_Information_Block
166 // First get the pointer to the TIB
167 quint8 *tib;
168# if defined(Q_CC_MINGW) // internal compiler error when using the intrinsics
169 __asm__("movq %%gs:0x30, %0" : "=r" (tib) : :);
170# else
171 tib = reinterpret_cast<quint8 *>(__readgsqword(0x30));
172# endif
173 // Then read the thread ID
174 tid = *reinterpret_cast<Qt::HANDLE *>(tib + 0x48);
175#elif defined(Q_PROCESSOR_X86_32) && defined(Q_OS_WIN)
176 // First get the pointer to the TIB
177 quint8 *tib;
178# if defined(Q_CC_MINGW) // internal compiler error when using the intrinsics
179 __asm__("movl %%fs:0x18, %0" : "=r" (tib) : :);
180# else
181 tib = reinterpret_cast<quint8 *>(__readfsdword(0x18));
182# endif
183 // Then read the thread ID
184 tid = *reinterpret_cast<Qt::HANDLE *>(tib + 0x24);
185#else
186#undef QT_HAS_FAST_CURRENT_THREAD_ID
187 tid = currentThreadIdImpl();
188#endif
189 return tid;
190}
191
192QT_END_NAMESPACE
193
194#endif // QTHREAD_H
195

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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