我正在接收来自两个不同来源(网络监听)的更新,在此基础上,我得到了一个类似这样的方法的回调:
void onUpdate(Update* update)
{
static MutexT lock;
static hash_set<UpdateID> set;
ScopedGuard _(lock); //lock here
hash_set<UpdateID>::iterator it = set.find(update->id);
if (it == set.end())
set.insert(update->id);
else
return;
listener->onUpdate(/*some stuff*/);
}
由于两个来源都在为您提供相同的更新,您希望避免在重复上进行通知,您希望在两个来源之间进行仲裁以使用最新的来源进行仲裁,无论是谁先给您,还有错过的更新,如果有的话消息来源可能不可靠。问题是,锁定每次更新都很昂贵,如果我绝对不希望重复onUpdate
次呼叫,是否可以绕过此锁?
(或者至少是一种降低成本的方法?)
答案 0 :(得分:2)
首先,锁不应该是静态的,它应该是一个成员变量。
通过使用读写器互斥,例如
,可以提高效率boost::shared_mutex mutex_;
std::unordered_set<UpdateID> set_;
void onUpdate(const Update& update)
{
boost::upgrade_lock<boost::shared_mutex> lock(mutex_);
auto it = set_.find(update.id);
if(it == set_.end())
{
boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(mutex_);
set.insert(update.id);
}
listener->onUpdate(/*some stuff*/);
}
答案 1 :(得分:0)
所以你只是不断地在哈希表中添加条目?从不删除它们?你的哈希表加载是什么样的?如果有足够的冲突,您的插入/查找性能将会降低。
如果您的信息流包含序列号,我认为您可以更好地跟踪差距(缺少序列号)而不是您实际看到的信息。在快速UDP端,当序列号有间隙时,在哈希表中记录丢失的消息,并在收到的每条消息上调用onUpdate()。在缓慢的TCP端,查看哈希表以查看消息是否填补了空白,如果它确实调用onUpdate()并从哈希表中删除该消息,否则什么也不做。
也就是说,可以使用无锁哈希表。不确定它们是否无锁,但Microsoft有concurrent_unordered_map(和concurrent_unordered_set),TBB有concurrent_hash_map。
答案 2 :(得分:-1)
通过检查插入条件两次,可以避免昂贵的锁定double-check-locking design-pattern。但更昂贵的是:锁定或找到。