Dav*_*eer 13 qt multithreading qtconcurrent qfuture
的QFuture类有方法,例如cancel(),progressValue()等.这些可明显通过被监测QFutureWatcher.但是,QtConcurrent::run()读取文档:
请注意,QtConcurrent :: run()返回的QFuture不支持取消,暂停或进度报告.返回的QFuture只能用于查询运行/完成状态和函数的返回值.
我实际上可以创建一个QFuture可以取消的方法,并报告单个长时间运行的操作的进度,这看起来是徒劳的.(看起来可能QtConcurrent::map()和类似的功能可以,但我只有一个长期运行的方法.)
(对于熟悉.Net的人来说,就像BackgroundWorker班级一样.)
有哪些选择?
Hat*_*ter 19
虽然这个问题已经发布和回答已经有一段时间了但我决定加入解决这个问题的方法,因为它与这里讨论的内容有很大不同,我认为对其他人可能有用.首先,我的方法的动机是,当框架已经有一些成熟的类比时,我通常不喜欢发明自己的API.所以问题是:我们有一个很好的API来控制由QFuture <>表示的后台计算,但是我们没有支持某些操作的对象.好吧,我们来做吧.查看QtConcurrent :: run内部的内容会使事情变得更加清晰:构造一个仿函数,包装到QRunnable中并在全局ThreadPool中运行.
所以我为我的"可控任务"创建了通用接口:
class TaskControl
{
public:
TaskControl(QFutureInterfaceBase *f) : fu(f) { }
bool shouldRun() const { return !fu->isCanceled(); }
private:
QFutureInterfaceBase *fu;
};
template <class T>
class ControllableTask
{
public:
virtual ~ControllableTask() {}
virtual T run(TaskControl& control) = 0;
};
Run Code Online (Sandbox Code Playgroud)
然后,按照qtconcurrentrunbase.h中的内容,我创建了q-runnable来运行这类任务(这段代码主要来自qtconcurrentrunbase.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;
};
Run Code Online (Sandbox Code Playgroud)
最后失踪的跑步者类将返回我们可控制的QFututre <> s:
class TaskExecutor {
public:
template <class T>
static QFuture<T> run(ControllableTask<T>* task) {
return (new RunControllableTask<T>(task))->start();
}
};
Run Code Online (Sandbox Code Playgroud)
用户应该子类化ControllableTask,实现后台例程,有时检查传递给TaskControl实例的TaskRtrol实例的方法shouldRun(),然后使用它:
QFututre<int> futureValue = TaskExecutor::run(new SomeControllableTask(inputForThatTask));
Run Code Online (Sandbox Code Playgroud)
然后她可以通过调用futureValue.cancel()来取消它,同时记住取消是优雅而不是立即.
对于长时间运行的单一任务,QThread这可能是您最好的选择。它没有内置的进度报告或取消功能,因此您必须自己动手。但对于简单的进度更新来说并不难。要取消任务,请检查可以通过任务循环中的调用线程设置的标志。
需要注意的一件事是,如果您重写QThread::run()并将任务放在那里,则无法从那里发出信号,因为 QThread 对象不是在它运行的线程中创建的,并且您无法从正在运行的线程中提取 QObject。关于这个问题有一篇很好的文章。
| 归档时间: |
|
| 查看次数: |
9511 次 |
| 最近记录: |