我需要以 CAS 方式更新 TBB 提供的 concurrent_hash_map 中的内容。也就是说,如果键已经存在,我会查看与键对应的值并在原子操作中更新值(如果值同时由于另一个线程做同样的事情而发生变化,我的操作应该会失败)。
换句话说,我为 insert 方法提供了一个“预期值”,它仅在当前值与预期值匹配时才更新该值。
在 TBB 的 concurrent_hash_map 中是否有实现这一点的方法?
非常感谢。
我需要以 CAS 方式更新 TBB 提供的 concurrent_hash_map 中的内容。也就是说,如果键已经存在,我会查看与键对应的值并在原子操作中更新值(如果值同时由于另一个线程做同样的事情而发生变化,我的操作应该会失败)。
换句话说,我为 insert 方法提供了一个“预期值”,它仅在当前值与预期值匹配时才更新该值。
在 TBB 的 concurrent_hash_map 中是否有实现这一点的方法?
非常感谢。
给定类型 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 有效。