我当前的代码如下所示
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
。