首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QtConcurrent映射和进度报告

QtConcurrent映射和进度报告
EN

Stack Overflow用户
提问于 2013-08-30 07:38:43
回答 2查看 1.7K关注 0票数 2

我正在使用QtConcurrent做一些沉重的背景图像处理,我想显示图像,而它的一部分正在逐步更新。图像的每一行分别计算,并传递一个函子。

为了计算完整的图像,我有一个传递给QtConcurrent的项目序列映射,每一行在完成计算时都会发出一个信号。

下面是类工作人员的实例化:

代码语言:javascript
复制
    //living in the main(gui) thread !
    Worker::Worker(VideoEngine* engine):_engine(engine){
        _watcher = new QFutureWatcher<bool>;
        _watcher->setPendingResultsLimit(200);
        connect(_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(onProgressUpdate(int)));
        connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
    }

下面是报告进度的插槽:

代码语言:javascript
复制
void Worker::onProgressUpdate(int i){
    if(i < (int)_rows.size() && i%10==0){
         cout << " index = " << i << " y = "<< _rows[i] << endl;
        _engine->checkAndDisplayProgress(_rows[i],i);
    }
}

现在使用:

代码语言:javascript
复制
void Worker::_computeTreeForFrame(.../*unrelevant args*/){
....
....
    _watcher->setFuture(
                   QtConcurrent::mapped(_sequence,
                   boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
    }
}

所有信号都会发出,但时隙onProgressUpdate只有在Qtconcurrent::the对序列中的所有项执行完时才会被调用。

当执行时,当序列正在处理时,它会有一个很大的延迟,然后所有的时隙都会被依次执行。

我尝试过所有类型的信号/插槽连接,但它们都没有改变这种行为。

有线索吗?

Shf建议+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++后的编辑

到目前为止,调用是在主线程(Gui)中进行的。我把电话改到:

代码语言:javascript
复制
_computeFrameWatcher->setFuture(QtConcurrent::run(_worker,&Worker::computeTreeForFrame));

由于_computeTreeForFrame现在在另一个线程中执行,所以我将调用更改为QtConcurrent::映射到:

代码语言:javascript
复制
_watcher->setFuture(QtConcurrent::mapped(_sequence,
                     boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();

这导致了与以前完全相同的行为。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++编辑后的马立克R建议+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

好的,我做了这样的测试,下面是我观察到的:

QtConcurrent::map :

  • 不会发出信号resultReadyAt(int)

QtConcurrent::mapped

  • 只有在完成时才会发出resultReadyAt(int)

如果对map函数的调用是在一个单独的线程中完成的,那么也会遇到相同的行为。

我还对信号progressValueChanged(int)进行了尝试,就像Qt progressDialog示例所显示的那样。信号progressValueChanged(int) 只发出图像中的2行(第一个和最后一个)。这真的很奇怪,因为在Qt进度对话框中,它是平稳地发出的。

我对Qt示例做了一些修改,以在另一个线程中启动map函数,而不是主线程,在这种情况下,它仍然工作得很好。

这个问题肯定是从别的地方产生的。

也许GUI事件循环正在做一些我不希望做的事情?我不知道是什么。

现在我将尝试QtConcurrent::mappedReduced并报告结果:-)

尝试QtConcurrent::MempdReducted+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++后进行+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++编辑

它不起作用,只有在完成"map“函数时才调用”还原“函数。换句话说,它所做的与以前的信号/时隙机制相同。

我现在的可能性越来越少了

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++编辑--我回到了一个与Qt进度对话框示例+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++一样接近的解决方案

如果我不能得到与Qt示例相同的行为,那么一定是出了问题。

下面是代码:

代码语言:javascript
复制
//created in the main thread! (gui)
Worker::Worker(VideoEngine* engine):_engine(engine),_watcher(0){
    _watcher = new QFutureWatcher<void>;
    _watcher->setPendingResultsLimit(200);
    connect(_watcher,SIGNAL(progressValueChanged(int)), _engine, 
                    SLOT(onProgressUpdate(int)));
    connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));

}

//executed on the main thread
void Worker::computeTreeForFrame(...){
...
_watcher->setFuture(QtConcurrent::map(_sequence,boost::bind(metaEnginePerRow,_1,output)));
...
}

给computeTreeForFrame的电话..。

代码语言:javascript
复制
...
    _worker->computeTreeForFrame();
...

这个调用是在一个时隙中完成的

它像前面所说的那样发出0行和最后一行的信号,但不会发出任何其他信号。

这不正是Qt示例所做的吗?

EN

回答 2

Stack Overflow用户

发布于 2013-08-30 12:36:19

从任务描述来看,您应该使用mappedReduced。问题是我看不出有什么好的方法能得到部分结果。解决这一问题的一种方法是发射信号形式的约简函数。

这条线可能会有所帮助。

票数 0
EN

Stack Overflow用户

发布于 2013-08-30 13:52:20

从文档的角度来看,QtConcurrent::mapped似乎并没有将VideoEngine::metaEnginePerRow放在另一个线程中。如果图像是在与GUI相同的线程中处理的,那么您的插槽将在处理后执行,无论您选择何种类型的连接,正如您所描述的那样。

解决方案要么是通过QtConcurrent::run在另一个线程中运行QtConcurrent::run(如我所理解的,主要处理函数),要么通过QObject::moveToThread()Worker对象放到另一个线程中。然后,您应该使用的连接类型是Qt::QueuedConnection (或者如果在连接之前将Worker放在另一个线程中,您甚至可以使用Qt::AutoConnectionor Qt::UniqueConnection连接,调用方和接收方将位于不同的线程中,因此qt将自动选择QueuedConnection`‘)

编辑:

我不确定,但是您的_watcher = new QFutureWatcher<bool>;仍然是在主线程中创建的,如果您调用

代码语言:javascript
复制
_watcher->setFuture(QtConcurrent::mapped(_sequence,
                 boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();

_watcher是否会将GUI线程设置为等待它创建的线程或执行此命令的线程。如果_watcher->setFuture(QtConcurrent::mapped(_sequence, boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));是函数的结束,那么是否需要_watcher->waitForFinished();呢?Qt将在线程执行后立即销毁线程,并将处理函数设置为运行,为什么要等待?

_computeFrameWatcher应为QFuture<void*>型。

EDIT2:

好吧,在我放弃之前,我建议你测试一下QObject::moveToThread

在调用_worker->computeTreeForFrame();之前,将其放到另一个线程中:

代码语言:javascript
复制
QThread *workerThread=new QThread();
_worker->moveToThread();
_worker->computeTreeForFrame();
/* connect _worker's finished signal with workerThread::quit and deleteLater slots */

_worker中的所有连接都应该是DirectConnection,_worker和main (GUI)线程之间的所有连接都应该与QueuedConnection连接。另外,在_worker构造函数中创建新线程并立即将其移动到另一个线程可能是好的,这样您就可以销毁线程in _worker的析构函数,而不必担心GUI线程中的线程问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18527473

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档