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);
168 SWIFT_VERIFY_X(!hasStarted(), Q_FUNC_INFO,
"Tried to start a worker that was already started");
169 if (hasStarted()) {
return; }
180 const QString ownerName =
181 m_owner->objectName().isEmpty() ? m_owner->metaObject()->className() : m_owner->objectName();
182 thread->setObjectName(ownerName +
": " + m_name);
185 moveToThread(thread);
187 connect(thread, &QThread::finished, &
m_updateTimer, &QTimer::stop);
189 connect(thread, &QThread::finished,
this, &CContinuousWorker::finish);
190 thread->start(priority);
198 if (this->thread() == m_owner->thread()) {
return; }
210 if (this->thread() == m_owner->thread()) {
return; }
215 QThread *workerThread = thread();
221 const QString name(this->
getName());
222 qint64 waitTime = QDateTime::currentMSecsSinceEpoch();
226 waitTime = QDateTime::currentMSecsSinceEpoch() - waitTime;
227 const QString msg = QStringLiteral(
"Waiting for quitAndWait of '%1' for %2ms").arg(name).arg(waitTime);
228 const QByteArray msgBA = msg.toLatin1();
237 Q_ASSERT_X(this->hasStarted(), Q_FUNC_INFO,
"Worker not yet started");
241 QPointer<CContinuousWorker> myself(
this);
243 if (!myself) {
return; }
250 if (updateTimeSecs < 0)
270 QPointer<CContinuousWorker> myself(
this);
273 if (!myself) {
return; }
279 void CContinuousWorker::finish()
283 QThread *workerThread = this->thread();
284 Q_ASSERT_X(m_owner->thread()->isRunning(), Q_FUNC_INFO,
"Owner thread's event loop already ended");
296 QMetaObject::invokeMethod(workerThread, [workerThread] {
298 workerThread->quit();
299 const bool ok = workerThread->wait(5000);
300 const QString as = QStringLiteral(
"Worker thread '%2' refuses to stop after worker finished")
301 .arg(workerThread->objectName());
302 const QByteArray asBA = as.toLatin1();
305 workerThread->deleteLater();
virtual void beforeQuit() noexcept
Called before quit is called.
void setEnabled(bool enabled)
Enabled (running)?
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.
QTimer m_updateTimer
timer which can be used by implementing classes
void stopUpdateTimer()
Safely stop update time.
void start(QThread::Priority priority=QThread::InheritPriority)
Starts a thread and moves the worker into it.
CContinuousWorker(QObject *owner, const QString &name)
Constructor.
void startUpdating(int updateTimeSecs)
Start updating (start/stop timer)
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.
void doIfNotFinished(F functor) const
Executes some code (in the caller's thread) if the task has not finished.
~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.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
#define SWIFT_AUDIT_X(COND, WHERE, WHAT)
A weaker kind of verify.
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.