Added some classes from a stackoverflow to utilize Qt's concurrency functions especially cancellable QFuture's

This commit is contained in:
eelke 2018-02-14 19:18:51 +01:00
parent ad3f605ada
commit 99d738ee65
5 changed files with 119 additions and 1 deletions

18
core/ControllableTask.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef CONTROLLABLETASK_H
#define CONTROLLABLETASK_H
/** From answer by Hatter
*
* https://stackoverflow.com/questions/5423058/qfuture-that-can-be-cancelled-and-report-progress
*/
#include "TaskControl.h"
template <class T>
class ControllableTask
{
public:
virtual ~ControllableTask() {}
virtual T run(TaskControl& control) = 0;
};
#endif // CONTROLLABLETASK_H

View file

@ -0,0 +1,45 @@
#ifndef RUNCONTROLLABLETASK_H
#define RUNCONTROLLABLETASK_H
/** From answer by Hatter
*
* https://stackoverflow.com/questions/5423058/qfuture-that-can-be-cancelled-and-report-progress
*/
#include <QFutureInterface>
#include <QRunnable>
#include "ControllableTask.h"
template <typename T>
class RunControllableTask : public QFutureInterface<T> , public QRunnable
{
public:
RunControllableTask(ControllableTask<T>* tsk) : task(tsk) { }
virtial ~RunControllableTask() { delete task; }
QFuture<T> start()
{
this->setRunnable(this);
this->reportStarted();
QFuture<T> future = this->future();
QThreadPool::globalInstance()->start(this, /*m_priority*/ 0);
return future;
}
void run()
{
if (this->isCanceled()) {
this->reportFinished();
return;
}
TaskControl control(this);
result = this->task->run(control);
if (!this->isCanceled()) {
this->reportResult(result);
}
this->reportFinished();
}
T result;
ControllableTask<T> *task;
};
#endif // RUNCONTROLLABLETASK_H

19
core/TaskControl.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef TASKCONTROL_H
#define TASKCONTROL_H
/** From answer by Hatter
*
* https://stackoverflow.com/questions/5423058/qfuture-that-can-be-cancelled-and-report-progress
*/
#include <QFutureInterfaceBase>
class TaskControl
{
public:
TaskControl(QFutureInterfaceBase *f) : fu(f) { }
bool shouldRun() const { return !fu->isCanceled(); }
private:
QFutureInterfaceBase *fu;
};
#endif // TASKCONTROL_H

32
core/TaskExecutor.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef TASKEXECUTOR_H
#define TASKEXECUTOR_H
/* From answer by Hatter
*
* https://stackoverflow.com/questions/5423058/qfuture-that-can-be-cancelled-and-report-progress
*/
#include "ControllableTask.h"
#include "RunControllableTask.h"
/**
* @brief The TaskExecutor class
*
* The user should sublass ControllableTask, implement background routine which checks sometimes
* method shouldRun() of TaskControl instance passed to run(TaskControl&) and then use it like:
*
* QFututre<int> futureValue = TaskExecutor::run(new SomeControllableTask(inputForThatTask));
*
* Then she may cancel it by calling futureValue.cancel(), bearing in mind that cancellation is
* graceful and not immediate.
*
*/
class TaskExecutor {
public:
template <class T>
static QFuture<T> run(ControllableTask<T>* task) {
return (new RunControllableTask<T>(task))->start();
}
};
#endif // TASKEXECUTOR_H

View file

@ -50,7 +50,11 @@ HEADERS += PasswordManager.h \
Expected.h \ Expected.h \
ExplainTreeModelItem.h \ ExplainTreeModelItem.h \
json/json.h \ json/json.h \
WorkManager.h WorkManager.h \
TaskControl.h \
ControllableTask.h \
RunControllableTask.h \
TaskExecutor.h
unix { unix {
target.path = /usr/lib target.path = /usr/lib