21 QSet<CWorkerBase *> CWorkerBase::s_allWorkers;
26 m_handle = GetCurrentThread();
36 const QString name = this->objectName();
39 auto handle = m_handle.load();
42 const auto status = WaitForSingleObject(handle, 0);
48 case WAIT_FAILED: qWarning() <<
"Thread" << name <<
"unspecified error";
break;
49 case WAIT_OBJECT_0: qWarning() <<
"Thread" << name <<
"unsafely terminated by program shutdown";
break;
50 case WAIT_TIMEOUT:
break;
58 const unsigned long timeoutMs = 5 * 1000;
59 const bool ok = wait(timeoutMs);
61 const QString as = QStringLiteral(
"Wait timeout after %1ms for '%2'").arg(timeoutMs).arg(name);
62 const QByteArray asBA = as.toLatin1();
68 CWorker *CWorker::fromTaskImpl(QObject *owner,
const QString &name,
int typeId,
69 const std::function<QVariant()> &task)
71 auto *worker =
new CWorker(task);
72 emit worker->aboutToStart();
76 if (typeId != QMetaType::Void) { worker->m_result = QVariant(QMetaType(typeId),
nullptr); }
78 const QString ownerName =
79 owner->objectName().isEmpty() ? owner->metaObject()->className() : owner->objectName();
80 thread->setObjectName(ownerName +
":" + name);
81 worker->setObjectName(name);
83 worker->moveToThread(thread);
84 const bool s = QMetaObject::invokeMethod(worker, &CWorker::ps_runTask);
85 Q_ASSERT_X(s, Q_FUNC_INFO,
"cannot invoke");
91 void CWorker::ps_runTask()
97 QThread *workerThread = this->thread();
98 Q_ASSERT_X(workerThread->thread()->isRunning(), Q_FUNC_INFO,
"Owner thread's event loop already ended");
111 QMetaObject::invokeMethod(workerThread, [workerThread] {
113 workerThread->quit();
114 const bool ok = workerThread->wait(5000);
115 const QString as = QStringLiteral(
"Worker thread '%2' refuses to stop after worker finished")
116 .arg(workerThread->objectName());
117 const QByteArray asBA = as.toLatin1();
120 workerThread->deleteLater();
136 std::promise<void> promise;
137 then([&] { promise.set_value(); });
138 promise.get_future().wait();
143 if (thread() != thread()->thread()) { thread()->requestInterruption(); }
149 if (thread() != thread()->thread()) { thread()->requestInterruption(); }
155 Q_ASSERT(thread() == QThread::currentThread());
156 return thread()->isInterruptionRequested();
161 Q_ASSERT_X(!name.isEmpty(), Q_FUNC_INFO,
"Empty name");
162 this->setObjectName(m_name);
179 const QString ownerName =
180 m_owner->objectName().isEmpty() ? m_owner->metaObject()->className() : m_owner->objectName();
181 thread->setObjectName(ownerName +
": " + m_name);
184 moveToThread(thread);
187 connect(thread, &QThread::finished,
this, &CContinuousWorker::finish);
188 thread->start(priority);
193 this->setEnabled(
false);
196 if (this->thread() == m_owner->thread()) {
return; }
205 this->setEnabled(
false);
208 if (this->thread() == m_owner->thread()) {
return; }
213 QThread *workerThread = thread();
219 const QString name(this->
getName());
220 qint64 waitTime = QDateTime::currentMSecsSinceEpoch();
222 waitTime = QDateTime::currentMSecsSinceEpoch() - waitTime;
223 const QString msg = QStringLiteral(
"Waiting for quitAndWait of '%1' for %2ms").arg(name).arg(waitTime);
224 const QByteArray msgBA = msg.toLatin1();
231 void CContinuousWorker::finish()
235 QThread *workerThread = this->thread();
236 Q_ASSERT_X(m_owner->thread()->isRunning(), Q_FUNC_INFO,
"Owner thread's event loop already ended");
248 QMetaObject::invokeMethod(workerThread, [workerThread] {
250 workerThread->quit();
251 const bool ok = workerThread->wait(5000);
252 const QString as = QStringLiteral(
"Worker thread '%2' refuses to stop after worker finished")
253 .arg(workerThread->objectName());
254 const QByteArray asBA = as.toLatin1();
257 workerThread->deleteLater();
virtual void beforeQuit() noexcept
Called before quit is called.
virtual void cleanup()
Called when the thread is finished.
void quit() noexcept final
Stops the thread the next time around its event loop. The thread and the worker will then be deleted.
virtual void initialize()
Called when the thread is started.
virtual unsigned long waitTimeoutMs() const
Wait time for quitAndWait, 0 means not waiting.
const QString & getName()
Name of the worker.
void quitAndWait() noexcept final
Calls quit() and blocks until the thread is finished.
void start(QThread::Priority priority=QThread::InheritPriority)
Starts a thread and moves the worker into it.
CContinuousWorker(QObject *owner, const QString &name)
Constructor.
static const QString & worker()
Background task.
Class for emitting a log message.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
Just a subclass of QThread whose destructor waits for the thread to finish.
~CRegularThread()
Destructor.
static bool isInThisThread(const QObject *toBeTested)
Is the current thread the object's thread?
CWorkerBase()
Constructor.
void aboutToStart()
Emitted when the task is about to start.
void then(T *context, F functor)
Connects to a functor or method which will be called when the task is finished.
void abandon() noexcept
Notify the task that its result is no longer needed, so it can finish early.
static const QStringList & getLogCategories()
Log categories.
void abandonAndWait() noexcept
Convenience to call abandon() followed by waitForFinished().
bool isAbandoned() const
For the task to check whether it can finish early.
bool hasStarted() const
True if the worker has started.
~CWorkerBase()
Destructor.
void setFinished()
Mark the task as finished.
void waitForFinished() noexcept
Blocks until the task is finished.
Class for doing some arbitrary parcel of work in its own thread.
Free functions in swift::misc.
#define SWIFT_AUDIT_X(COND, WHERE, WHAT)
A weaker kind of verify.
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.