summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/compat/removed_api.cpp7
-rw-r--r--src/corelib/thread/qrunnable.cpp22
-rw-r--r--src/corelib/thread/qrunnable.h63
-rw-r--r--tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp19
4 files changed, 91 insertions, 20 deletions
diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp
index fdbe5de41c..e1d9c9eccf 100644
--- a/src/corelib/compat/removed_api.cpp
+++ b/src/corelib/compat/removed_api.cpp
@@ -509,6 +509,13 @@ QByteArray QMessageAuthenticationCode::hash(const QByteArray &msg, const QByteAr
qToByteArrayViewIgnoringNull(key), method);
}
+#include "qrunnable.h"
+
+QRunnable *QRunnable::create(std::function<void()> functionToRun)
+{
+ return QRunnable::create<std::function<void()>>(std::move(functionToRun));
+}
+
#include "qstring.h"
qsizetype QString::toUcs4_helper(const ushort *uc, qsizetype length, uint *out)
diff --git a/src/corelib/thread/qrunnable.cpp b/src/corelib/thread/qrunnable.cpp
index 5bb354cbb1..718802010a 100644
--- a/src/corelib/thread/qrunnable.cpp
+++ b/src/corelib/thread/qrunnable.cpp
@@ -77,31 +77,17 @@ QRunnable::~QRunnable()
\sa autoDelete(), QThreadPool
*/
-class FunctionRunnable : public QRunnable
-{
- std::function<void()> m_functionToRun;
-public:
- FunctionRunnable(std::function<void()> functionToRun) : m_functionToRun(std::move(functionToRun))
- {
- }
- void run() override
- {
- m_functionToRun();
- }
-};
-
/*!
+ \fn template<typename Callable> QRunnable *QRunnable::create(Callable &&callableToRun);
\since 5.15
- Creates a QRunnable that calls \a functionToRun in run().
+ Creates a QRunnable that calls \a callableToRun in run().
Auto-deletion is enabled by default.
+ \note In Qt versions prior to 6.6, this method took copyable functions only.
+
\sa run(), autoDelete()
*/
-QRunnable *QRunnable::create(std::function<void()> functionToRun)
-{
- return new FunctionRunnable(std::move(functionToRun));
-}
QT_END_NAMESPACE
diff --git a/src/corelib/thread/qrunnable.h b/src/corelib/thread/qrunnable.h
index c77f8eea0a..131efdedb7 100644
--- a/src/corelib/thread/qrunnable.h
+++ b/src/corelib/thread/qrunnable.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRUNNABLE_H
@@ -6,6 +6,7 @@
#include <QtCore/qglobal.h>
#include <functional>
+#include <type_traits>
QT_BEGIN_NAMESPACE
@@ -19,12 +20,70 @@ public:
constexpr QRunnable() noexcept = default;
virtual ~QRunnable();
+#if QT_CORE_REMOVED_SINCE(6, 6)
static QRunnable *create(std::function<void()> functionToRun);
-
+#endif
+ template <typename Callable>
+ static QRunnable *create(Callable &&functionToRun);
bool autoDelete() const { return m_autoDelete; }
void setAutoDelete(bool autoDelete) { m_autoDelete = autoDelete; }
+
+protected:
+ // Type erasure, to only instantiate a non-virtual class per Callable:
+ class QGenericRunnableHelperBase
+ {
+ using OpFn = void(*)(const QGenericRunnableHelperBase *);
+ OpFn runFn;
+ OpFn destroyFn;
+ protected:
+ constexpr explicit QGenericRunnableHelperBase(OpFn fn, OpFn del) noexcept : runFn(fn), destroyFn(del) {}
+ ~QGenericRunnableHelperBase() = default;
+ public:
+ void run() { runFn(this); }
+ void destroy() { destroyFn(this); }
+ };
+
+ template <typename Callable>
+ class QGenericRunnableHelper : public QGenericRunnableHelperBase
+ {
+ Callable m_functionToRun;
+ public:
+ template <typename UniCallable>
+ QGenericRunnableHelper(UniCallable &&functionToRun) noexcept :
+ QGenericRunnableHelperBase(
+ [](const QGenericRunnableHelperBase *that) { static_cast<const QGenericRunnableHelper*>(that)->m_functionToRun(); },
+ [](const QGenericRunnableHelperBase *that) { delete static_cast<const QGenericRunnableHelper*>(that); }),
+ m_functionToRun(std::forward<UniCallable>(functionToRun))
+ {
+ }
+ };
+};
+
+class QGenericRunnable : public QRunnable
+{
+ QGenericRunnableHelperBase *runHelper;
+public:
+ QGenericRunnable(QGenericRunnableHelperBase *runner) noexcept: runHelper(runner)
+ {
+ }
+ ~QGenericRunnable() override
+ {
+ runHelper->destroy();
+ }
+ void run() override
+ {
+ runHelper->run();
+ }
};
+template <typename Callable>
+QRunnable *QRunnable::create(Callable &&functionToRun)
+{
+ return new QGenericRunnable(
+ new QGenericRunnableHelper<std::decay_t<Callable>>(
+ std::forward<Callable>(functionToRun)));
+}
+
QT_END_NAMESPACE
#endif
diff --git a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp
index fc41d545fd..42f2545574 100644
--- a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp
+++ b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp
@@ -6,6 +6,7 @@
#include <QSemaphore>
#include <qelapsedtimer.h>
+#include <qrunnable.h>
#include <qthreadpool.h>
#include <qstring.h>
#include <qmutex.h>
@@ -45,6 +46,7 @@ public:
private slots:
void runFunction();
void runFunction2();
+ void runFunction3();
void createThreadRunFunction();
void runMultiple();
void waitcomplete();
@@ -173,6 +175,23 @@ void tst_QThreadPool::runFunction2()
QCOMPARE(localCount, 1);
}
+struct DeleteCheck
+{
+ static bool s_deleted;
+ ~DeleteCheck() { s_deleted = true; }
+};
+bool DeleteCheck::s_deleted = false;
+
+void tst_QThreadPool::runFunction3()
+{
+ std::unique_ptr<DeleteCheck> ptr(new DeleteCheck);
+ {
+ TestThreadPool manager;
+ manager.start(QRunnable::create([my_ptr = std::move(ptr)]() { }));
+ }
+ QVERIFY(DeleteCheck::s_deleted);
+}
+
void tst_QThreadPool::createThreadRunFunction()
{
{