我正在使用QtConcurrent做一些沉重的背景图像处理,我想显示图像,而它的一部分正在逐步更新。图像的每一行分别计算,并传递一个函子。
为了计算完整的图像,我有一个传递给QtConcurrent的项目序列映射,每一行在完成计算时都会发出一个信号。
下面是类工作人员的实例化:
//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()));
}下面是报告进度的插槽:
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);
}
}现在使用:
void Worker::_computeTreeForFrame(.../*unrelevant args*/){
....
....
_watcher->setFuture(
QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
}
}所有信号都会发出,但时隙onProgressUpdate只有在Qtconcurrent::the对序列中的所有项执行完时才会被调用。
当执行时,当序列正在处理时,它会有一个很大的延迟,然后所有的时隙都会被依次执行。
我尝试过所有类型的信号/插槽连接,但它们都没有改变这种行为。
有线索吗?
Shf建议+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++后的编辑
到目前为止,调用是在主线程(Gui)中进行的。我把电话改到:
_computeFrameWatcher->setFuture(QtConcurrent::run(_worker,&Worker::computeTreeForFrame));由于_computeTreeForFrame现在在另一个线程中执行,所以我将调用更改为QtConcurrent::映射到:
_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示例相同的行为,那么一定是出了问题。
下面是代码:
//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的电话..。
...
_worker->computeTreeForFrame();
...这个调用是在一个时隙中完成的。
它像前面所说的那样发出0行和最后一行的信号,但不会发出任何其他信号。
这不正是Qt示例所做的吗?
发布于 2013-08-30 12:36:19
从任务描述来看,您应该使用mappedReduced。问题是我看不出有什么好的方法能得到部分结果。解决这一问题的一种方法是发射信号形式的约简函数。
这条线可能会有所帮助。
发布于 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>;仍然是在主线程中创建的,如果您调用
_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();之前,将其放到另一个线程中:
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线程中的线程问题。
https://stackoverflow.com/questions/18527473
复制相似问题