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