2013-03-03 66 views
2

我需要以CAS方式更新由TBB提供的concurrent_hash_map中的內容。也就是說,如果一個鍵已經存在,我查看與該鍵相對應的值並在原子操作中更新該值(如果由於另一個線程做同樣的事情而導致該值同時發生變化,那麼我的操作將失敗)。tbb併發哈希映射:如何比較和設置

換句話說,我爲插入方法提供了一個「預期值」,並且只有在當前值與期望值匹配時才更新值。

TBB的concurrent_hash_map中有一個實現這個嗎?

非常感謝。

回答

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; 
} 

它工作了我用gcc 4.7編譯時使用「g ++ -std = C++ 0x」。

+1

這就是我一直在尋找的。非常感謝。 – 2013-03-06 02:24:10