[英]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.