我正在尝试使用 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
起成为类(class)成员提供确定并发任务是否仍在运行的方法。
总而言之,从构造函数中删除这一行:
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;
}
关于c++ - QFuture 信号在错误的时间发出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28951580/