File indexing completed on 2024-05-05 12:27:24
0001 /* -*- C++ -*- 0002 This file is part of ThreadWeaver. It implements the Thread class. 0003 0004 SPDX-FileCopyrightText: 2004-2013 Mirko Boehm <mirko@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 0008 $Id: Thread.cpp 25 2005-08-14 12:41:38Z mirko $ 0009 */ 0010 0011 #include "thread.h" 0012 0013 #include <QCoreApplication> 0014 #include <QDebug> 0015 #include <QPointer> 0016 0017 #include "debuggingaids.h" 0018 #include "exception.h" 0019 #include "job.h" 0020 #include "threadweaver.h" 0021 #include "weaver.h" 0022 0023 using namespace ThreadWeaver; 0024 0025 class Q_DECL_HIDDEN Thread::Private 0026 { 0027 public: 0028 explicit Private(Weaver *theParent) 0029 : parent(theParent) 0030 , id(makeId()) 0031 , job(nullptr) 0032 { 0033 Q_ASSERT(parent); 0034 } 0035 0036 Weaver *parent; 0037 const unsigned int id; 0038 JobPointer job; 0039 QMutex mutex; 0040 0041 static unsigned int makeId() 0042 { 0043 static QAtomicInt s_id(1); 0044 return s_id.fetchAndAddRelease(1); 0045 } 0046 }; 0047 0048 Thread::Thread(Weaver *parent) 0049 : QThread() // no parent, because the QObject hierarchy of this thread 0050 // does not have a parent (see QObject::pushToThread) 0051 , d(new Private(parent)) 0052 { 0053 const QString queueName = 0054 parent->objectName().isEmpty() ? QString::fromLatin1("Queue(0x%1)").arg(quintptr(parent), 0, 16, QChar::fromLatin1('0')) : parent->objectName(); 0055 setObjectName(QString::fromLatin1("%1[%2]").arg(queueName).arg(QString::number(id()), 2, QChar::fromLatin1('0'))); 0056 } 0057 0058 Thread::~Thread() 0059 { 0060 delete d; 0061 } 0062 0063 unsigned int Thread::id() const 0064 { 0065 return d->id; // id is const 0066 } 0067 0068 void Thread::run() 0069 { 0070 Q_ASSERT(d->parent); 0071 Q_ASSERT(QCoreApplication::instance() != nullptr); 0072 d->parent->threadEnteredRun(this); 0073 0074 #if THREADWEAVER_BUILD_DEPRECATED_SINCE(5, 80) 0075 Q_EMIT started(this); 0076 #endif 0077 0078 TWDEBUG(3, "Thread::run [%u]: running.\n", id()); 0079 0080 bool wasBusy = false; 0081 while (true) { 0082 TWDEBUG(3, "Thread::run [%u]: trying to execute the next job.\n", id()); 0083 0084 try { 0085 // the assignment is intentional: newJob needs to go out of scope at the end of the if statement 0086 if (JobPointer newJob = d->parent->applyForWork(this, wasBusy)) { 0087 QMutexLocker l(&d->mutex); 0088 Q_UNUSED(l); 0089 d->job = newJob; 0090 } else { 0091 break; 0092 } 0093 } catch (AbortThread &) { 0094 break; 0095 } 0096 0097 wasBusy = true; 0098 d->job->execute(d->job, this); 0099 JobPointer oldJob; 0100 { // When finally destroying the last reference to d->job, do not hold the mutex. 0101 // It may trigger destruction of the job, which can execute arbitrary code. 0102 QMutexLocker l(&d->mutex); 0103 Q_UNUSED(l); 0104 oldJob = d->job; 0105 d->job.clear(); 0106 } 0107 oldJob.clear(); 0108 } 0109 TWDEBUG(3, "Thread::run [%u]: exiting.\n", id()); 0110 } 0111 0112 void Thread::requestAbort() 0113 { 0114 QMutexLocker l(&d->mutex); 0115 Q_UNUSED(l); 0116 if (d->job) { 0117 d->job->requestAbort(); 0118 } 0119 } 0120 0121 #include "moc_thread.cpp"