0

いくつかのジオメトリの反復生成をスレッド化しました。レンダリングには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
}
4

2 に答える 2

2

コードに少なくとも1つの欠陥があります。countクリティカルセクションにrender属します。つまり、同時アクセスから保護する必要があります。

待機中のスレッドがさらにあると想定しwc.wait(&renderLock);ます。誰かがどこかで実行しwc.wakeAll();ます。すべてのスレッドがウェイクアップされます。少なくとも1つのスレッドがnotFinishedtrueと見なされ(コードのいずれかが意味をなす場合、これは可能である必要があります)、実行に戻ります。

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

2回目にスレッドが戻ったとき、彼にはロックがありませんrenderLock。したがって、 Kamil Klimekは正しいです。つまり、保持していないミューテックスで待機を呼び出します

コンストラクターのロックを解除し、条件を呼び出す前にロックする必要があります。ロックする場所はどこでもrenderlock、スレッドは保持されるべきではありませんthreadlock

于 2013-03-19T15:02:21.490 に答える
0

問題は、グローバルQMutexが1つだけではなく、スレッドごとに1つの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
}
于 2013-03-20T16:12:28.687 に答える