我正在尝试使用QT的QFuture和QFutureWatcher来实现带有通知的工作线程,但是通知不是在正确的时间发出的!

我正在从菜单处理程序中调用loadFile(QString),并期望负载在工作线程中发生,这就是发生的情况。但是ibLoadFinished()是在执行connect之后而不是退出后立即被调用的
LoadFromDisk()。 (磁盘访问在IBF构造函数中完成)。

我究竟做错了什么?

ImageViewer.h:

class ImageViewer : public QMainWindow
{
  Q_OBJECT
public:
  static IBF* LoadFromDisk(const QString& filename);

private:
  QFuture<IBF*> ibfLoadedFuture;
  QFutureWatcher<IBF*> ibfLoadedFutureWatcher;

private slots:
  //...
  Q_SLOT void ibLoadFinished();
}


ImageViewer.cpp:

ImageViewer::ImageViewer() : ibfLoadedFutureWatcher(this)
{
  // ...
  connect(&ibfLoadedFutureWatcher, SIGNAL(finished()), this, SLOT(ibLoadFinished()));
  ibfLoadedFutureWatcher.setFuture(ibfLoadedFuture);
  //...
}

bool ImageViewer::loadFile(const QString& filename)
{
  if (ibfLoadedFuture.isRunning())
    return false;
  ibfLoadedFuture = QtConcurrent::run(LoadFromDisk, filename);
  return true;
}

IBF* ImageViewer::LoadFromDisk(const QString &filename)
{
  IBF* ibf = new IBF(filename);
  return ibf;
}

void ImageViewer::ibLoadFinished()
{
  IBF* ibf(ibfLoadedFuture);
  process(*ibf);
  delete ibf;
}

最佳答案

尽管未在文档中明确说明,但只要从QFutureWatcher::setFuture获得新的QFuture时都必须调用QtConcurrent::run(),这意味着您无法像完成操作那样在setFuture的构造函数中调用ImageViewer。同样,不必将QFuture保留为类的成员,因为QFutureWatcher提供了确定并发任务是否仍在运行的方法。

总而言之,从构造函数中删除此行:
ibfLoadedFutureWatcher.setFuture(ibfLoadedFuture);

然后将loadFile的实现更改为以下内容:

bool ImageViewer::loadFile(const QString& filename)
{
  if (ibfLoadedFutureWatcher.isRunning())
    return false;
  QFuture<IBF*> ibfLoadedFuture = QtConcurrent::run(LoadFromDisk, filename);
  ibfLoadFutureWatcher.setFuture(ibfLoadedFuture);
  return true;
}


另外,您可以使用QFutureWatcher::result()从并发运行中获得结果:

void ImageViewer::ibLoadFinished()
{
  IBF* ibf = ibfLoadedFutureWatcher.result();
  process(*ibf);
  delete ibf;
}

09-26 06:58