Tasking: Introduce ConcurrentCall

It substitutes Utils::Async, but is Utils independent.

The ConcurrentCall class is prepared to work with TaskTree.
Provide the task tree adapter for the ConcurrentCall class.
Register the task inside the Tasking namespace under
the ConcurrentCallTask name.

This class introduces the dependency to Qt::Concurrent,
otherwise Tasking namespace is independent on Qt::Concurrent.
Possibly, may be added into Qt::Concurrent lib,
as a wrapper around the QtConcurrent::run() call.

Change-Id: I4511ff0430e78346aa6a4fae1a9d5370fdd08506
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Jarek Kobus
2023-06-03 09:36:39 +02:00
parent 8d02d96127
commit b7bd30aeb8
4 changed files with 105 additions and 3 deletions

View File

@@ -1,9 +1,10 @@
add_qtc_library(Tasking OBJECT add_qtc_library(Tasking OBJECT
# Never add dependencies to non-Qt libraries for this library # Never add dependencies to non-Qt libraries for this library
DEPENDS Qt::Core DEPENDS Qt::Concurrent Qt::Core
PUBLIC_DEFINES TASKING_LIBRARY PUBLIC_DEFINES TASKING_LIBRARY
SOURCES SOURCES
barrier.cpp barrier.h barrier.cpp barrier.h
concurrentcall.h
tasking_global.h tasking_global.h
tasktree.cpp tasktree.h tasktree.cpp tasktree.h
) )

View File

@@ -34,7 +34,7 @@ private:
int m_current = -1; int m_current = -1;
}; };
class TASKING_EXPORT BarrierTaskAdapter : public Tasking::TaskAdapter<Barrier> class TASKING_EXPORT BarrierTaskAdapter : public TaskAdapter<Barrier>
{ {
public: public:
BarrierTaskAdapter() { connect(task(), &Barrier::done, this, &TaskInterface::done); } BarrierTaskAdapter() { connect(task(), &Barrier::done, this, &TaskInterface::done); }

View File

@@ -0,0 +1,100 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include "tasking_global.h"
#include "tasktree.h"
#include <QtConcurrent>
namespace Tasking {
// This class introduces the dependency to Qt::Concurrent, otherwise Tasking namespace
// is independent on Qt::Concurrent.
// Possibly, it could be placed inside Qt::Concurrent library, as a wrapper around
// QtConcurrent::run() call.
template <typename ResultType>
class ConcurrentCall
{
Q_DISABLE_COPY_MOVE(ConcurrentCall)
public:
ConcurrentCall() = default;
template <typename Function, typename ...Args>
void setConcurrentCallData(Function &&function, Args &&...args)
{
return wrapConcurrent(std::forward<Function>(function), std::forward<Args>(args)...);
}
void setThreadPool(QThreadPool *pool) { m_threadPool = pool; }
ResultType result() const
{
return m_future.resultCount() ? m_future.result() : ResultType();
}
QFuture<ResultType> future() const { return m_future; }
private:
template <typename Function, typename ...Args>
void wrapConcurrent(Function &&function, Args &&...args)
{
m_startHandler = [=] {
if (m_threadPool)
return QtConcurrent::run(m_threadPool, function, args...);
return QtConcurrent::run(function, args...);
};
}
template <typename Function, typename ...Args>
void wrapConcurrent(std::reference_wrapper<const Function> &&wrapper, Args &&...args)
{
m_startHandler = [=] {
if (m_threadPool) {
return QtConcurrent::run(m_threadPool,
std::forward<const Function>(wrapper.get()), args...);
}
return QtConcurrent::run(std::forward<const Function>(wrapper.get()), args...);
};
}
template <typename T>
friend class ConcurrentCallTaskAdapter;
std::function<QFuture<ResultType>()> m_startHandler;
QThreadPool *m_threadPool = nullptr;
QFuture<ResultType> m_future;
};
template <typename ResultType>
class ConcurrentCallTaskAdapter : public TaskAdapter<ConcurrentCall<ResultType>>
{
public:
~ConcurrentCallTaskAdapter() {
if (m_watcher) {
m_watcher->cancel();
m_watcher->waitForFinished();
}
}
void start() {
if (!this->task()->m_startHandler) {
emit this->done(false); // TODO: Add runtime assert
return;
}
m_watcher.reset(new QFutureWatcher<ResultType>);
this->connect(m_watcher.get(), &QFutureWatcherBase::finished, this, [this] {
emit this->done(!m_watcher->isCanceled());
m_watcher.release()->deleteLater();
});
this->task()->m_future = this->task()->m_startHandler();
m_watcher->setFuture(this->task()->m_future);
}
private:
std::unique_ptr<QFutureWatcher<ResultType>> m_watcher;
};
} // namespace Tasking
TASKING_DECLARE_TEMPLATE_TASK(ConcurrentCallTask, Tasking::ConcurrentCallTaskAdapter);

View File

@@ -1,11 +1,12 @@
QtcLibrary { QtcLibrary {
name: "Tasking" name: "Tasking"
Depends { name: "Qt"; submodules: ["core"] } Depends { name: "Qt"; submodules: ["concurrent", "core"] }
cpp.defines: base.concat("TASKING_LIBRARY") cpp.defines: base.concat("TASKING_LIBRARY")
files: [ files: [
"barrier.cpp", "barrier.cpp",
"barrier.h", "barrier.h",
"concurrentcall.h",
"tasking_global.h", "tasking_global.h",
"tasktree.cpp", "tasktree.cpp",
"tasktree.h", "tasktree.h",