Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qthread.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qthread.h"
6#include "qthreadstorage.h"
7#include "qmutex.h"
8#include "qreadwritelock.h"
10#include "qbindingstorage.h"
11
12#include <qeventloop.h>
13
14#include "qthread_p.h"
15#include "private/qcoreapplication_p.h"
16
17#include <limits>
18
20
21/*
22 QPostEventList
23*/
24
26{
27 int priority = ev.priority;
28 if (isEmpty() ||
29 constLast().priority >= priority ||
30 insertionOffset >= size()) {
31 // optimization: we can simply append if the last event in
32 // the queue has higher or equal priority
33 append(ev);
34 } else {
35 // insert event in descending priority order, using upper
36 // bound for a given priority (to ensure proper ordering
37 // of events with the same priority)
38 QPostEventList::iterator at = std::upper_bound(begin() + insertionOffset, end(), ev);
39 insert(at, ev);
40 }
41}
42
43
44/*
45 QThreadData
46*/
47
48QThreadData::QThreadData(int initialRefCount)
49 : _ref(initialRefCount), loopLevel(0), scopeLevel(0),
50 eventDispatcher(nullptr),
51 quitNow(false), canWait(true), isAdopted(false), requiresCoreApplication(true)
52{
53 // fprintf(stderr, "QThreadData %p created\n", this);
54}
55
57{
58#if QT_CONFIG(thread)
59 Q_ASSERT(_ref.loadRelaxed() == 0);
60#endif
61
62 // In the odd case that Qt is running on a secondary thread, the main
63 // thread instance will have been dereffed asunder because of the deref in
64 // QThreadData::current() and the deref in the pthread_destroy. To avoid
65 // crashing during QCoreApplicationData's global static cleanup we need to
66 // safeguard the main thread here.. This fix is a bit crude, but it solves
67 // the problem...
69 QCoreApplicationPrivate::theMainThread.storeRelease(nullptr);
70 QCoreApplicationPrivate::theMainThreadId.storeRelaxed(nullptr);
72 }
73
74 // ~QThread() sets thread to nullptr, so if it isn't null here, it's
75 // because we're being run before the main object itself. This can only
76 // happen for QAdoptedThread. Note that both ~QThreadPrivate() and
77 // ~QObjectPrivate() will deref this object again, but that is acceptable
78 // because this destructor is still running (the _ref sub-object has not
79 // been destroyed) and there's no reentrancy. The refcount will become
80 // negative, but that's acceptable.
82 thread.storeRelease(nullptr);
83 delete t;
84
85 for (int i = 0; i < postEventList.size(); ++i) {
86 const QPostEvent &pe = postEventList.at(i);
87 if (pe.event) {
88 --pe.receiver->d_func()->postedEvents;
89 pe.event->m_posted = false;
90 delete pe.event;
91 }
92 }
93
94 // fprintf(stderr, "QThreadData %p destroyed\n", this);
95}
96
98{
99#if QT_CONFIG(thread)
100 (void) _ref.ref();
101 Q_ASSERT(_ref.loadRelaxed() != 0);
102#endif
103}
104
106{
107#if QT_CONFIG(thread)
108 if (!_ref.deref())
109 delete this;
110#endif
111}
112
119
120/*
121 QAdoptedThread
122*/
123
126{
127 // thread should be running and not finished for the lifetime
128 // of the application (even if QCoreApplication goes away)
129#if QT_CONFIG(thread)
130 d_func()->running = true;
131 d_func()->finished = false;
132 init();
133 d_func()->m_statusOrPendingObjects.setStatusAndClearList(
135#endif
136 // fprintf(stderr, "new QAdoptedThread = %p\n", this);
137}
138
140{
141 // fprintf(stderr, "~QAdoptedThread = %p\n", this);
142}
143
144#if QT_CONFIG(thread)
146{
147 // this function should never be called
148 qFatal("QAdoptedThread::run(): Internal error, this implementation should never be called.");
149}
150#endif
151
153 : threadData(threadData)
154{
155 ++threadData->scopeLevel;
156 qCDebug(lcDeleteLater) << "Increased" << threadData->thread
157 << "scope level to" << threadData->scopeLevel;
158}
159
161{
162 --threadData->scopeLevel;
163 qCDebug(lcDeleteLater) << "Decreased" << threadData->thread
164 << "scope level to" << threadData->scopeLevel;
165}
166
167#if QT_CONFIG(thread)
168/*
169 QThreadPrivate
170*/
171
173 : QObjectPrivate(), running(false), finished(false),
174 isInFinish(false), interruptionRequested(false),
175 exited(false), returnCode(-1),
176 stackSize(0), priority(QThread::InheritPriority), data(d)
177{
178
179// INTEGRITY doesn't support self-extending stack. The default stack size for
180// a pthread on INTEGRITY is too small so we have to increase the default size
181// to 128K.
182#ifdef Q_OS_INTEGRITY
183 stackSize = 128 * 1024;
184#elif defined(Q_OS_RTEMS)
185 Q_CONSTINIT static bool envStackSizeOk = false;
186 static const int envStackSize = qEnvironmentVariableIntValue("QT_DEFAULT_THREAD_STACK_SIZE", &envStackSizeOk);
187 if (envStackSizeOk)
188 stackSize = envStackSize;
189#endif
190
191#if defined (Q_OS_WIN)
192 handle = 0;
193 id = 0;
194 waiters = 0;
195 terminationEnabled = true;
196 terminatePending = false;
197#endif
198
199 if (!data)
200 data = new QThreadData;
201}
202
204{
205 // access to m_statusOrPendingObjects cannot race with anything
206 // unless there is already a potential use-after-free bug, as the
207 // thread is in the process of being destroyed
208 delete m_statusOrPendingObjects.list();
209 data->deref();
210}
211
423{
425 Q_ASSERT(data != nullptr);
426 return data->thread.loadAcquire();
427}
428
442{
444}
445
454 : QObject(*(new QThreadPrivate), parent)
455{
456 Q_D(QThread);
457 // fprintf(stderr, "QThreadData %p created for thread %p\n", d->data, this);
458 d->data->thread.storeRelaxed(this);
459}
460
465 : QObject(dd, parent)
466{
467 Q_D(QThread);
468 // fprintf(stderr, "QThreadData %p taken from private data for thread %p\n", d->data, this);
469 d->data->thread.storeRelaxed(this);
470}
471
491{
492 Q_D(QThread);
493 {
494 QMutexLocker locker(&d->mutex);
495 if (d->isInFinish) {
496 locker.unlock();
497 wait();
498 locker.relock();
499 }
500 if (d->running && !d->finished && !d->data->isAdopted)
501 qFatal("QThread: Destroyed while thread is still running");
502
503 d->data->thread.storeRelease(nullptr);
504 }
505}
506
513bool QThread::isFinished() const
514{
515 Q_D(const QThread);
516 QMutexLocker locker(&d->mutex);
517 return d->finished || d->isInFinish;
518}
519
526bool QThread::isRunning() const
527{
528 Q_D(const QThread);
529 QMutexLocker locker(&d->mutex);
530 return d->running && !d->isInFinish;
531}
532
553void QThread::setStackSize(uint stackSize)
554{
555 Q_D(QThread);
556 QMutexLocker locker(&d->mutex);
557 Q_ASSERT_X(!d->running, "QThread::setStackSize",
558 "cannot change stack size while the thread is running");
559 d->stackSize = stackSize;
560}
561
569{
570 Q_D(const QThread);
571 QMutexLocker locker(&d->mutex);
572 return d->stackSize;
573}
574
582{
583
584 if (auto pendingObjects = list()) {
585 for (auto obj: *pendingObjects)
586 QObjectPrivate::get(obj)->reinitBindingStorageAfterThreadMove();
587 delete pendingObjects;
588 }
589 // synchronizes-with the load-acquire in bindingStatus():
590 data.store(encodeBindingStatus(status), std::memory_order_release);
591}
592
606int QThread::exec()
607{
608 Q_D(QThread);
610
611 QMutexLocker locker(&d->mutex);
612 d->m_statusOrPendingObjects.setStatusAndClearList(status);
613 d->data->quitNow = false;
614 if (d->exited) {
615 d->exited = false;
616 return d->returnCode;
617 }
618 locker.unlock();
619
620 QEventLoop eventLoop;
621 int returnCode = eventLoop.exec();
622
623 locker.relock();
624 d->exited = false;
625 d->returnCode = -1;
626 return returnCode;
627}
628
629
638{
639 if (auto status = bindingStatus())
640 return status;
641 List *objectList = list();
642 if (!objectList) {
643 objectList = new List();
644 objectList->reserve(8);
645 data.store(encodeList(objectList), std::memory_order_relaxed);
646 }
647 objectList->push_back(object);
648 return nullptr;
649}
650
656{
657 List *objectList = list();
658 if (!objectList)
659 return;
660 auto it = std::remove(objectList->begin(), objectList->end(), object);
661 objectList->erase(it, objectList->end());
662}
663
665{
666 if (auto status = m_statusOrPendingObjects.bindingStatus())
667 return status;
669 return m_statusOrPendingObjects.addObjectUnlessAlreadyStatus(obj);
670}
671
673{
674 if (m_statusOrPendingObjects.bindingStatus())
675 return;
677 m_statusOrPendingObjects.removeObject(obj);
678}
679
680
703void QThread::exit(int returnCode)
704{
705 Q_D(QThread);
706 QMutexLocker locker(&d->mutex);
707 d->exited = true;
708 d->returnCode = returnCode;
709 d->data->quitNow = true;
710 for (int i = 0; i < d->data->eventLoops.size(); ++i) {
711 QEventLoop *eventLoop = d->data->eventLoops.at(i);
712 eventLoop->exit(returnCode);
713 }
714}
715
726void QThread::quit()
727{ exit(); }
728
740void QThread::run()
741{
742 (void) exec();
743}
744
764void QThread::setPriority(Priority priority)
765{
766 if (priority == QThread::InheritPriority) {
767 qWarning("QThread::setPriority: Argument cannot be InheritPriority");
768 return;
769 }
770 Q_D(QThread);
771 QMutexLocker locker(&d->mutex);
772 if (!d->running) {
773 qWarning("QThread::setPriority: Cannot set priority, thread is not running");
774 return;
775 }
776 d->setPriority(priority);
777}
778
788{
789 Q_D(const QThread);
790 QMutexLocker locker(&d->mutex);
791
792 // mask off the high bits that are used for flags
793 return Priority(d->priority & 0xffff);
794}
795
936int QThread::loopLevel() const
937{
938 Q_D(const QThread);
939 return d->data->eventLoops.size();
940}
941
955Qt::HANDLE QThreadPrivate::threadId() const
956{
957 return data->threadId.loadRelaxed();
958}
959
966bool QThread::isCurrentThread() const
967{
968 Q_D(const QThread);
969 return QThread::currentThreadId() == d->threadId();
970}
971
972#else // QT_CONFIG(thread)
973
975 : QObject(*(new QThreadPrivate), parent)
976{
977 Q_D(QThread);
978 d->data->thread.storeRelaxed(this);
979}
980
982{
983
984}
985
987{
988
989}
990
992{
993 return 0;
994}
995
997{
998 Q_D(QThread);
1000 d->running = true;
1001}
1002
1004{
1005
1006}
1007
1009{
1010
1011}
1012
1013void QThread::exit(int returnCode)
1014{
1015 Q_D(QThread);
1016 d->data->quitNow = true;
1017 for (int i = 0; i < d->data->eventLoops.size(); ++i) {
1018 QEventLoop *eventLoop = d->data->eventLoops.at(i);
1019 eventLoop->exit(returnCode);
1020 }
1021}
1022
1024{
1026 return false;
1027}
1028
1030{
1031 return QObject::event(event);
1032}
1033
1034Qt::HANDLE QThread::currentThreadIdImpl() noexcept
1035{
1036 return Qt::HANDLE(currentThread());
1037}
1038
1040{
1041 return QThreadData::current()->thread.loadAcquire();
1042}
1043
1045{
1046 return true;
1047}
1048
1050{
1051 return 1;
1052}
1053
1055{
1056
1057}
1058
1060{
1061 return false;
1062}
1063
1065{
1066 Q_D(const QThread);
1067 return d->running;
1068}
1069
1071{
1072
1073}
1074
1076{
1077 return false;
1078}
1079
1081{
1082}
1083
1084// No threads: so we can just use static variables
1085Q_CONSTINIT static QThreadData *data = nullptr;
1086
1087QThreadData *QThreadData::current(bool createIfNecessary)
1088{
1089 if (!data && createIfNecessary) {
1090 data = new QThreadData;
1091 data->thread = new QAdoptedThread(data);
1092 data->threadId.storeRelaxed(Qt::HANDLE(data->thread.loadAcquire()));
1093 data->deref();
1094 data->isAdopted = true;
1095 if (!QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
1096 QCoreApplicationPrivate::theMainThread.storeRelease(data->thread.loadRelaxed());
1097 QCoreApplicationPrivate::theMainThreadId.storeRelaxed(data->threadId.loadRelaxed());
1098 }
1099 }
1100 return data;
1101}
1102
1104{
1105 delete data;
1106 data = 0;
1107}
1108
1113 : QObject(dd, parent)
1114{
1115 Q_D(QThread);
1116 // fprintf(stderr, "QThreadData %p taken from private data for thread %p\n", d->data, this);
1117 d->data->thread.storeRelaxed(this);
1118}
1119
1123
1125{
1126 data->thread.storeRelease(nullptr); // prevent QThreadData from deleting the QThreadPrivate (again).
1127 delete data;
1128}
1129
1131{
1133}
1134
1136{
1137 return 0;
1138}
1139
1140#endif // QT_CONFIG(thread)
1141
1149{
1150 Q_D(const QThread);
1151 return d->data->eventDispatcher.loadRelaxed();
1152}
1153
1167{
1168 Q_D(QThread);
1169 if (d->data->hasEventDispatcher()) {
1170 qWarning("QThread::setEventDispatcher: An event dispatcher has already been created for this thread");
1171 } else {
1173 if (eventDispatcher->thread() == this) // was the move successful?
1174 d->data->eventDispatcher = eventDispatcher;
1175 else
1176 qWarning("QThread::setEventDispatcher: Could not move event dispatcher to target thread");
1177 }
1178}
1179
1188#if QT_CONFIG(thread)
1189
1194{
1195 if (event->type() == QEvent::Quit) {
1196 quit();
1197 return true;
1198 } else {
1199 return QObject::event(event);
1200 }
1201}
1202
1217{
1218 Q_D(QThread);
1219 if (d->threadId() == QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
1220 qWarning("QThread::requestInterruption has no effect on the main thread");
1221 return;
1222 }
1223 QMutexLocker locker(&d->mutex);
1224 if (!d->running || d->finished || d->isInFinish)
1225 return;
1226 d->interruptionRequested.store(true, std::memory_order_relaxed);
1227}
1228
1256{
1257 Q_D(const QThread);
1258 // fast path: check that the flag is not set:
1259 if (!d->interruptionRequested.load(std::memory_order_relaxed))
1260 return false;
1261 // slow path: if the flag is set, take into account run status:
1262 QMutexLocker locker(&d->mutex);
1263 return d->running && !d->finished && !d->isInFinish;
1264}
1265
1288class QThreadCreateThread : public QThread
1289{
1290public:
1291 explicit QThreadCreateThread(std::future<void> &&future)
1292 : m_future(std::move(future))
1293 {
1294 }
1295
1296 ~QThreadCreateThread()
1297 {
1298 requestInterruption();
1299 quit();
1300 wait();
1301 }
1302
1303private:
1304 void run() override
1305 {
1306 m_future.get();
1307 }
1308
1309 std::future<void> m_future;
1310};
1311
1312QThread *QThread::createThreadImpl(std::future<void> &&future)
1313{
1314 return new QThreadCreateThread(std::move(future));
1315}
1316
1325QDaemonThread::QDaemonThread(QObject *parent)
1326 : QThread(parent)
1327{
1328 // QThread::started() is emitted from the thread we start
1330 this,
1331 [](){ QThreadData::current()->requiresCoreApplication = false; },
1333}
1334
1335QDaemonThread::~QDaemonThread()
1336{
1337}
1338
1339#endif // QT_CONFIG(thread)
1340
1342
1343#include "moc_qthread.cpp"
QAdoptedThread(QThreadData *data=nullptr)
Definition qthread.cpp:124
bool ref() noexcept
bool deref() noexcept
T loadRelaxed() const noexcept
Type loadAcquire() const noexcept
void storeRelease(Type newValue) noexcept
static QBasicAtomicPointer< void > theMainThreadId
static QBasicAtomicPointer< QThread > theMainThread
\inmodule QtCore
\inmodule QtCore
Definition qeventloop.h:16
int exec(ProcessEventsFlags flags=AllEvents)
Enters the main event loop and waits until exit() is called.
void exit(int returnCode=0)
Tells the event loop to exit with a return code.
\inmodule QtCore
Definition qcoreevent.h:45
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
const QPostEvent & constLast() const noexcept
Definition qlist.h:650
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:488
iterator end()
Definition qlist.h:626
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
iterator begin()
Definition qlist.h:625
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1389
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1598
bool moveToThread(QThread *thread QT6_DECL_NEW_OVERLOAD_TAIL)
Changes the thread affinity for this object and its children and returns true on success.
Definition qobject.cpp:1643
void addEvent(const QPostEvent &ev)
Definition qthread.cpp:25
qsizetype insertionOffset
Definition qthread_p.h:71
QObject * receiver
Definition qthread_p.h:42
QScopedScopeLevelCounter(QThreadData *threadData)
Definition qthread.cpp:152
iterator end()
Definition qset.h:140
static Q_AUTOTEST_EXPORT QThreadData * current(bool createIfNecessary=true)
Definition qthread.cpp:1087
QAtomicPointer< QAbstractEventDispatcher > eventDispatcher
Definition qthread_p.h:325
QThreadData(int initialRefCount=1)
Definition qthread.cpp:48
void deref()
Definition qthread.cpp:105
static void clearCurrentThreadData()
Definition qthread.cpp:1103
QAtomicPointer< void > threadId
Definition qthread_p.h:324
QPostEventList postEventList
Definition qthread_p.h:322
void ref()
Definition qthread.cpp:97
QAtomicPointer< QThread > thread
Definition qthread_p.h:323
QAbstractEventDispatcher * createEventDispatcher()
Definition qthread.cpp:113
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
QThreadPrivate(QThreadData *d=nullptr)
Definition qthread.cpp:1120
void removeObjectWithPendingBindingStatusChange(QObject *)
Definition qthread_p.h:270
QThreadData * data
Definition qthread_p.h:264
QBindingStatus * addObjectWithPendingBindingStatusChange(QObject *)
Definition qthread_p.h:269
void terminate()
Definition qthread.cpp:1003
static bool isMainThread()
bool isInterruptionRequested() const
Definition qthread.cpp:1075
void start(Priority=InheritPriority)
Definition qthread.cpp:996
QAbstractEventDispatcher * eventDispatcher() const
Definition qthread.cpp:1148
bool isRunning() const
Definition qthread.cpp:1064
bool isCurrentThread() const
Definition qthread.cpp:1044
static int idealThreadCount() noexcept
Definition qthread.cpp:1049
bool event(QEvent *event) override
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qthread.cpp:1029
virtual void run()
Definition qthread.cpp:986
bool isFinished() const
Definition qthread.cpp:1059
static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION
Definition qthread.h:149
static QThread * currentThread()
Definition qthread.cpp:1039
static void setTerminationEnabled(bool enabled=true)
Definition qthread.cpp:1080
@ InheritPriority
Definition qthread.h:51
static void yieldCurrentThread()
Definition qthread.cpp:1054
bool wait(QDeadlineTimer deadline=QDeadlineTimer(QDeadlineTimer::Forever))
Definition qthread.cpp:1023
QThread(QObject *parent=nullptr)
Definition qthread.cpp:974
uint stackSize() const
Definition qthread.cpp:1135
Priority priority() const
void finished(QPrivateSignal)
int exec()
Definition qthread.cpp:991
void setPriority(Priority priority)
void requestInterruption()
Definition qthread.cpp:1070
void setStackSize(uint stackSize)
Definition qthread.cpp:1130
void quit()
Definition qthread.cpp:1008
int loopLevel() const
void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
Definition qthread.cpp:1166
void started(QPrivateSignal)
void exit(int retcode=0)
Definition qthread.cpp:1013
List * list() const noexcept
Definition qthread_p.h:135
void removeObject(QObject *object)
void setStatusAndClearList(QBindingStatus *status) noexcept
QBindingStatus * addObjectUnlessAlreadyStatus(QObject *object)
QBindingStatus * bindingStatus() const noexcept
Definition qthread_p.h:124
std::vector< QObject * > List
Definition qthread_p.h:103
QSet< QString >::iterator it
Combined button and popup list for selecting options.
QTCONCURRENT_RUN_NODISCARD auto run(QThreadPool *pool, Function &&f, Args &&...args)
Q_AUTOTEST_EXPORT QBindingStatus * getBindingStatus(QBindingStatusAccessToken)
void * HANDLE
@ DirectConnection
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
static QDBusError::ErrorType get(const char *name)
static Q_CONSTINIT QBasicAtomicInt running
#define qWarning
Definition qlogging.h:166
#define qFatal
Definition qlogging.h:168
#define qCDebug(category,...)
GLuint64 GLenum void * handle
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
struct _cl_event * event
GLhandleARB obj
[2]
GLdouble GLdouble t
Definition qopenglext.h:243
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define Q_UNUSED(x)
unsigned int uint
Definition qtypes.h:34
QList< int > list
[14]
QFuture< void > future
[5]
QDeadlineTimer deadline(30s)
QObject::connect nullptr
QMutex mutex
[2]
QReadWriteLock lock
[0]
dialog exec()
QAction * at