簡體   English   中英

盡管有wakeAll調用,仍有2個線程在QWaitCondition上等待

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

您的代碼中至少存在一個缺陷。 countrender屬於臨界區,這意味着需要保護它們不受並發訪問的影響。

假設有更多線程在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM