简体   繁体   中英

2 threads left hanging waiting on QWaitCondition in spite of wakeAll calls

I have threaded iterative generation of some geometries. I use VTK for rendering. After each iteration I would like to display (render) the current progress. My approach works as expected until the last 2 threads are left hanging waiting for QWaitCondition. They are blocked, even though their status in QWaitCondition's queue is wokenUp (inspected through debugger). I suspect that number of 2 threads is somehow connected with my processor's 4 cores.

Simplified code is below. What am I doing wrong and how to fix it?

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
}

There is at least one defect in your code. count and render belong to the critical section, which means they need to be protected from concurrent access.

Assume there are more threads waiting on wc.wait(&renderLock); . Someone somewhere execute wc.wakeAll(); . ALL the threads are woken up. Assume at least one thread sees notFinished as true (if any of your code make sense, this must be possible) and go back to execute :

    threadLock.lock(); //lock scene
    mesh[meshIndex]->setGeometry(g);
    render=true;
    threadLock.unlock();
    wc.wait(&renderLock) <----OOPS...

The second time the thread comes back, he doesn't have the lock renderLock . So Kamil Klimek is right: you call wait on a mutex you don't hold .

You should remove the lock in constructor, and lock before the calling the condition. Wherever you lock renderlock , the thread should not hold threadlock .

The catch was that I needed one QMutex per thread, and not just one global QMutex. The corrected code is below. Thanks for help 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
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM