2

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

换句话说,我为 insert 方法提供了一个“预期值”,它仅在当前值与预期值匹配时才更新该值。

在 TBB 的 concurrent_hash_map 中是否有实现这一点的方法?

非常感谢。

4

1 回答 1

4

给定类型 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 有效。

于 2013-03-04T21:19:38.217 回答