Create any callable using QRunnable::create
The overhead of making new custom classes appears to be less than constructing a generic std::function. [ChangeLog][QtCore][QRunnable] QRunnable::create can now take non-copyable functions as argument. Task-number: QTBUG-112302 Change-Id: Ied870f13ca6c7eaa14ed6eff9c4e676c7b73881c Reviewed-by: Marc Mutz <marc.mutz@qt.io>
This commit is contained in:
parent
5c4a94ba85
commit
c080d1e64d
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user