我需要以CAS方式更新TBB提供的concurrent_hash_map中的内容。也就是说,如果一个键已经存在,我会查看与该键对应的值并在原子操作中更新该值(如果由于另一个线程执行相同的操作而同时值发生变化,则我的操作应该失败)。 / p>
换句话说,我为insert方法提供了“期望值”,只有当前值与期望值匹配时才更新值。
在TBB的concurrent_hash_map中有没有实现这个目的?
非常感谢。
答案 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对我有用。