[英]2 threads left hanging waiting on QWaitCondition in spite of wakeAll calls
我有线程迭代生成一些几何。 我使用VTK进行渲染。 在每次迭代后,我想显示(渲染)当前进度。 我的方法按预期工作,直到最后2个线程挂起等待QWaitCondition。 它们被阻止,即使它们在QWaitCondition的队列中的状态是wokenUp(通过调试器检查)。 我怀疑2个线程的数量与我的处理器的4个内核有某种联系。
简化代码如下。 我做错了什么以及如何解决?
class Logic
{
QMutex threadLock, renderLock;
//SOLUTION: renderLock should be per thread, not global like this!
QWaitCondition wc;
bool render;
...
}
Logic::Logic()
{
...
renderLock.lock(); //needs to be locked for QWaitCondition
}
void Logic::timerProc()
{
static int count=0;
if (render||count>10) //render wanted or not rendered in a while
{
threadLock.lock();
vtkRenderWindow->Render();
render=false;
count=0;
wc.wakeAll();
threadLock.unlock();
}
else
count++;
}
double Logic::makeMesh(int meshIndex)
{
while (notFinished)
{
...(calculate g)
threadLock.lock(); //lock scene
mesh[meshIndex]->setGeometry(g);
render=true;
threadLock.unlock();
wc.wait(&renderLock); //wait until rendered
}
return g.size;
}
void Logic::makeAllMeshes()
{
vector<QFuture<double>> r;
for (int i=0; i<meshes.size(); i++)
{
QFuture<double> future = QtConcurrent::run<double>(this, &Logic::makeMesh, i);
r.push_back(future);
}
while(any r is not finished)
QApplication::processEvents(); //give timer a chance
}
您的代码中至少存在一个缺陷。 count
和render
属于临界区,这意味着需要保护它们不受并发访问的影响。
假设有更多线程在wc.wait(&renderLock);
上等待wc.wait(&renderLock);
。 有人在某处执行wc.wakeAll();
。 所有线程都被唤醒了。 假设至少有一个线程看到notFinished
为true(如果你的任何代码有意义,那一定是可能的)并返回执行:
threadLock.lock(); //lock scene
mesh[meshIndex]->setGeometry(g);
render=true;
threadLock.unlock();
wc.wait(&renderLock) <----OOPS...
线程第二次回来时,他没有锁定renderLock
。 所以卡米尔克利梅克是对的: 你打电话等待一个你没有持有的互斥锁 。
您应该在构造函数中删除锁,并在调用条件之前锁定。 无论你在哪里锁定renderlock
,线程都不应该持有threadlock
。
问题在于我每个线程需要一个QMutex,而不仅仅是一个全局QMutex。 更正后的代码如下。 感谢UmNyobe的帮助!
class Logic
{
QMutex threadLock;
QWaitCondition wc;
bool render;
...
}
//nothing in constructor related to threading
void Logic::timerProc()
{
//count was a debugging workaround and is not needed
if (render)
{
threadLock.lock();
vtkRenderWindow->Render();
render=false;
wc.wakeAll();
threadLock.unlock();
}
}
double Logic::makeMesh(int meshIndex)
{
QMutex renderLock; //fix
renderLock.lock(); //fix
while (notFinished)
{
...(calculate g)
threadLock.lock(); //lock scene
mesh[meshIndex]->setGeometry(g);
render=true;
threadLock.unlock();
wc.wait(&renderLock); //wait until rendered
}
return g.size;
}
void Logic::makeAllMeshes()
{
vector<QFuture<double>> r;
for (int i=0; i<meshes.size(); i++)
{
QFuture<double> future = QtConcurrent::run<double>(this, &Logic::makeMesh, i);
r.push_back(future);
}
while(any r is not finished)
QApplication::processEvents(); //give timer a chance
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.