2

我从两个不同的来源(网络侦听)接收更新,在这些来源上我得到一个类似于这样的方法的回调:

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调用,有没有办法绕过这个锁定?

(或者至少是一种降低成本的方法?)

4

3 回答 3

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*/);
}
于 2012-09-11T19:15:57.220 回答
0

所以你只是不断地向你的哈希表添加条目?从不删除它们?你的哈希表加载是什么样的?如果发生足够多的冲突,您的插入/查找性能将会下降。

如果您的流有序列号,我认为您最好跟踪间隙(缺少序列号)而不是您实际看到的消息。在快速 UDP 端,当序列号有间隙时,将丢失的消息记录在哈希表中,并在收到的每条消息上调用 onUpdate()。在慢速 TCP 端,查看哈希表以查看消息是否填补了空白,如果它确实调用 onUpdate() 并从哈希表中删除该消息,否则什么也不做。

也就是说,无锁哈希表是可能的。不确定它们是无锁的,但微软有concurrent_unordered_map(和concurrent_unordered_set),TBB 有concurrent_hash_map

于 2012-09-11T21:21:55.843 回答
-1

双重检查锁定设计模式,您可以通过两次检查插入条件来避免昂贵的锁定。但更昂贵的是:锁定或查找。

于 2012-09-11T19:16:26.200 回答