tbb并发哈希映射:如何比较和设置

时间:2013-03-03 12:51:52

标签: concurrency hashmap tbb

我需要以CAS方式更新TBB提供的concurrent_hash_map中的内容。也就是说,如果一个键已经存在,我会查看与该键对应的值并在原子操作中更新该值(如果由于另一个线程执行相同的操作而同时值发生变化,则我的操作应该失败)。 / p>

换句话说,我为insert方法提供了“期望值”,只有当前值与期望值匹配时才更新值。

在TBB的concurrent_hash_map中有没有实现这个目的?

非常感谢。

1 个答案:

答案 0 :(得分:3)

给定Key和T类型,以下代码实现了目标,假设类型T是支持tbb :: atomic的类型。

class AtomicValue {
    mutable tbb::atomic<T> content;
public:
    AtomicValue() {}
    AtomicValue( T value ) {content=value;}
    bool cas( T value, T comparand ) const {
        return content.compare_and_swap(value,comparand)==comparand;
    }
};

typedef tbb::concurrent_hash_map<Key,AtomicValue> table;

bool update( table& x, Key key, T value, T comparand ) {
    table::const_accessor a;
    if( !x.insert(a,table::value_type(key,value) ) ) {
        // value is already there
        return a->second.cas(value,comparand);
    }
    return true;
}

棘手的部分是使用const_accessor进行更新。使用常规访问器将序列化更新。但是const_accessor允许多个线程同时访问同一个表条目。它被称为“const_accessor”,因为通常的用例涉及读取值。但是这里的代码使用CAS来仲裁更新。包装类“AtomicValue”允许在const对象上执行CAS。

类似的解决方案应该适用于tbb :: concurrent_unordered_map,如果非阻塞是关键标准,这可能会更好,因为concurrent_unordered_map具有非阻塞实现。

更好的是,如果您拥有最新的TBB 支持constexpr和默认/删除成员函数的C ++ 11功能的编译器,则以下内容应该有效:

 typedef tbb::concurrent_unordered_map<Key,tbb::atomic<T> > table;

bool update( table& x, Key key, T value, T comparand ) {
    auto p = x.insert(table::value_type(key,value) );
    if( !p.second ) {
        // value is already there
        return p.first->second.compare_and_swap(value,comparand) == comparand;
    }
    return true;
}

使用“g ++ -std = c ++ 0x”编译时,gcc 4.7对我有用。