QFuture信号在错误的时间发射

QFuture signal is emitted in wrong times

本文关键字:时间 发射 错误 信号 QFuture      更新时间:2023-10-16

我正在尝试使用 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();
}

图像查看器.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;
}

虽然文档中没有明确说明,但每当从QtConcurrent::run()获得新QFuture时都必须调用QFutureWatcher::setFuture,这意味着您不能像以前那样在构造函数中调用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;
}