1

私の現在のコードは次のようになります

void XXX::waitForUpdates()
{
    boost::unique_lock<boost::mutex> lock(mutex_agentDone);
    while(!allAgentUpdatesDone()) {
        COND_VAR_AGENT_DONE.wait(lock);
    }
}

void XXX::onAgentUpdate(YYY argums){
    Agent * target = const_cast<Agent*>(argums.GetAgent());
    boost::unique_lock<boost::mutex> lock(mutex_agentDone);
    REGISTERED_AGENTS.setDone(target,true);
        COND_VAR_AGENT_DONE.notify_all();
}

onAgentUpdateが1 秒間に約 100 万回呼び出される場合を除いて、すべて問題ありません。パフォーマンスと最適化について心配する必要があります。

したがって、チェックを行うwait(lock)totimed_waitバージョンを変更すると、毎秒数十万単位で呼び出される s をallAgentUpdatesDone()スキップできると考えました。.notify()あえぎません、これはシミュレーション フレームワークです :)

次に、myseld に尋ねました。何のために が必要mutex_agentDoneですか? 次のように 2 つの関数を変更できます。

void XXX::waitForUpdates()
{
    //this lock will become practically useless, coz there is no other 
    // mutex_agentDone being locked in any other function.
    boost::unique_lock<boost::mutex> lock(mutex_agentDone);
    while(!allAgentUpdatesDone()) {     
        COND_VAR_AGENT_DONE.timed_wait(lock,some_time_interval);
    }
}

void XXX::onAgentUpdate(YYY argums){
    Agent * target = const_cast<Agent*>(argums.GetAgent());
    REGISTERED_AGENTS.setDone(target,true)
}

問題は、これは安全ですか?

ありがとうございました

ちょっとしたメモ: 2 つの関数の残りの操作は、独自のミューテックスによって既に保護されていると仮定します (は、すべてのアクセサーと反復メソッドで呼び出される独自のミューテックスREGISTERED_AGENTSを持つクラス オブジェクトであるため、REGISTERED_AGENTSと同じものを使用して同じことを反復しています)containermutexallAgentUpdatesDone()containermutex

4

2 に答える 2

2

あなたはこれを行うことができます:

void XXX::waitForUpdates()
{
    boost::unique_lock<boost::mutex> lock(mutex_agentDone);
    while(!allAgentUpdatesDone()) {
        ++waiters;
        COND_VAR_AGENT_DONE.wait(lock);
        --waiters;
    }
}

void XXX::onAgentUpdate(YYY argums){
    Agent * target = const_cast<Agent*>(argums.GetAgent());
    boost::unique_lock<boost::mutex> lock(mutex_agentDone);
    REGISTERED_AGENTS.setDone(target,true);
    if (waiters != 0)
        COND_VAR_AGENT_DONE.notify_all();
}

ミューテックスはwaitersカウントを保護します。必ずゼロに設定して開始してください。

条件変数にはすでにこのようなものが含まれていると予想されますが、呼び出すオーバーヘッドだけnotify_allでもかなりの量になる可能性があります。

これは、ほとんどの場合ウェイターがいないことを前提としています。ほとんどの場合 がallAgentUpdatesDone返されるという問題がある場合は、すべての更新が完了するまでfalse呼び出さnotify_allないでください。

于 2013-09-19T06:33:26.530 に答える
2

私は C++11 のアトミックについてはあまり詳しくありませんが、Solaris では、このように volatile bool と membar ops を組み合わせて使用​​できます。

volatile bool done = false;
void XXX::waitForUpdates()
{
//    boost::unique_lock<boost::mutex> lock(mutex_agentDone);
    while(!allAgentUpdatesDone()) {
               while ( !done )
               {
                     usleep(1000000);
                     membar_consumer();
               }
    }
}

void XXX::onAgentUpdate(YYY argums){
    Agent * target = const_cast<Agent*>(argums.GetAgent());
    //boost::unique_lock<boost::mutex> lock(mutex_agentDone);
    membar_producer();
    REGISTERED_AGENTS.setDone(target,true);
        done = true;
}

ありがとうニラジ・ラティ

于 2013-09-19T06:12:03.930 に答える