有没有办法在没有锁定的情况下在两个不同的更新源之间进行仲裁?

时间:2012-09-11 19:09:12

标签: c++ multithreading thread-safety locking lock-free

我正在接收来自两个不同来源(网络监听)的更新,在此基础上,我得到了一个类似这样的方法的回调:

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次呼叫,是否可以绕过此锁?

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

3 个答案:

答案 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。但更昂贵的是:锁定或找到。