我当前的代码如下所示

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秒被调用一百万次时,我不得不担心性能和优化。

因此,我想出了如果我将wait(lock)更改为进行timed_wait检查的allAgentUpdatesDone()版本,那么我可以跳过.notify(),否则每秒调用数十万次!不要大惊小怪,这是一个模拟框架:)

然后我问myseld:我需要mutex_agentDone吗?我可以这样修改两个函数:
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)
}

问题是:这样安全吗?

谢谢

一个小注意事项:
假定这两个函数中的其余操作已经由它们自己的互斥体保护了(REGISTERED_AGENTS是一个类对象,具有container并在每个访问器和迭代方法中调用其自己的mutex,因此allAgentUpdatesDone()使用相同的container遍历同一mutex作为Registration_AGENTS)

最佳答案

你可以这样做:

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

10-08 08:20
查看更多