3

我有一些任务,从QtConcurrent::run(). 任务有QFutureWatcher。我知道QFutureWatcher只能观看一个Future,但是当我从 UI 启动相同的任务时,如何在每个任务上创建 `QFutureWatcher*?是吗 :

QFutureWatcher<void> *watcher = new QFutureWatcher;
watcher->setFuture(future);
QVector<QFutureWatcher<void>*> watchers;
watchers.push_back(watcher); // vector with pointers to each tasks watchers

或者是其他东西? * 我的麻烦是我从我的代码开始每个任务,但任务是使用外部 DLL 函数执行的。而且我没有 API 来停止任务。QFutureWatcher在我收到完成信号后,我只能等待任务结束并关闭任务并释放所有相关数据。

此时,我使用了两个 QFutureWatchers - 一个正在观看第一个运行的任务,另一个 - 如果第一个任务没有结束则启动,并使用临时观察者和临时槽观察第二个任务(代码相同,我创建它只是为了接收另一个观察者带有相关数据的信号),直到第一个任务结束。它观看了相同的代码,但我必须复制它以等待第一个任务结束,因为QFutureWatcher没有完成信号的队列和相关的 watcher.result()`s ..

1) Qt 有任何队列任务机制吗?或者我怎样才能捕捉到多个任务的未来?

2)QtConcurrent::run没有 cancel() 插槽。我可以对一个序列项使用映射/映射函数吗?映射 API 是否已排队处理任务/已完成信号?我怎么能意识到这一点?谢谢!

4

2 回答 2

3

1)你可以使用这样的东西(只是代码草稿):

class MultiWatcher
  : public QThread
{
  Q_OBJECT

signals:
  void allDone();

public:
  void run() override;
  QFutureSynchronizer _sync;
};

void MultiWatcher::run()
{
  _sync.waitForFinished();
  emit allDone();
}


class Test
  : public QObject
{
  Q_OBJECT
public:
  //...
  void do();
  void onDone();
};

void Test::do()
{
  // fill some futures
  auto w = new MultiWatcher();
  w->_sync.addFuture( f1 ); // Not thread-safe
  w->_sync.addFuture( f2 );
  w->_sync.addFuture( f3 );
  // ...
  connect( w, &MultiWatcher::allDone, this, &Test::onDone );
  w->start();
}

void Test::onDone()
{
  sender()->deleteLater();
  qDebug() << "All futures are done";
}

//...
test->do();

2)有QFuture::cancel()映射计算的方法。从你的问题中不清楚,你如何得到期货,所以很难说更多。如果您有一些问题,您可以阅读Qt 中的并发并提出更多问题。

QFuture::cancel将无法使用QtConcurrent::run,您需要在线程代码中设计另一种中断机制。例如:

std::atomic_bool _isRunning = true; // somewhere in code

void MyWorker::doWork()
{
  while (_isRunning)
  {
    // Do next step of computation
  }
}

// Use _isRunning = false; to interrupt. It's thread-safe.

但是中断您不管理的代码(来自外部 .dll)是有风险的,因为您可能有很多泄漏。这就是 QtConcurrent 中没有“终止”API 的原因。

PS请不要写我对 QThread 做错了。一切都很好。我知道我在做什么。这是一个很好的示例,其中继承QThread是可以的。

于 2016-07-13T08:52:54.243 回答
1

Qt 有任何队列任务机制吗?

Qt 提供了强大的信号&槽框架,非常适合这样的应用。

实施步骤:

  1. 创建一个 Worker 类(QObject 派生),它有一个executeTask(int foo, QString bar)包含任务实现的槽。
  2. 实例化一个QThread并将您的 Worker 类实例移动到该 QThread 使用QObject::moveToThread
  3. 启动线程
  4. 通过发出连接到的信号executeTask或调用方法QMetaMethod::invoke来运行任务executeTask

笔记:

  • Qt 会将您的调用排队executeTask(只要您使用 4. 中描述的方法之一)并且它们将按顺序执行。
  • 要快速终止您的 Worker,您可以使用QThread::requestInterruption并在您的executeTask方法中使用QThread::isInterruptionRequested.
  • 要强制终止您的 Worker,您可以使用QThread::terminate.
  • 否则,使用QThread::quitandQThread::wait优雅地终止工作人员并等待所有任务都已执行。
于 2016-07-13T09:31:30.037 回答