TBB之concurrent_hash_map

Intel TBB 提供高并发的容器类,Windows或者Linux线程能使用这些容器类或者和基于task编程相结合(TBB)。

一个并发容器允许多线程同时对容器访问和更改条例,典型的C++STL容器类不允许 并发更新,尝试并行更改他们引起恶化容器。STL容器能使用互斥锁来包装,目的让他们安全访问,通过只让一个线程同时操作一个容器,但是这种方式消除了并行,限制了并行提速。

Intel TBB提供的容器有更高水准的并发性,通过以下方法:

  • Fine-grained locking:只通过锁需要锁的部分,在容器上实现多线程操作,一旦多线程访问不同部分,他们能同步进行。
  • Lock-free techniques:改正其他干扰线程的影响。

注意高并发容器是有代价的,他们典型的有更高的消耗比STL容器,对高并发容器操作比STL容器消耗更多,因此,当使用高并发容器比STL容器提速的时候,他们是优于串行的性能。

concurrent_hash_map

concurrenthashmap<Key,T,HashCompare> 是一个hash表,允许并行访问,表是一个从Key到类型T的映射,类型HashCompare定义怎样hash一个Key和怎样比较2个Key。

下面的例子建立一个concurrent_hash_map,这个Key是字符串,对应的数据是矩阵Data中字符串出现的次数。

#include "tbb/concurrent_hash_map.h"
#include "tbb/blocked_range.h"
#include "tbb/parallel_for.h"
#include <string>

using namespace tbb;
using namespace std;

// Structure that defines hashing and comparison operations for user's
type.
struct MyHashCompare {
    static size_t hash( const string& x ) {
        size_t h = 0;
        for( const char* s = x.c_str(); *s; ++s )
            h = (h*17)^*s;
        return h;
    }
    //! True if strings are equal
    static bool equal( const string& x, const string& y ) {
        return x==y;
    }
};
// A concurrent hash table that maps strings to ints.
typedef concurrent_hash_map<string,int,MyHashCompare> StringTable;

// Function object for counting occurrences of strings.
struct Tally {
    StringTable& table;
    Tally( StringTable& table_ ) : table(table_) {}
    void operator()( const blocked_range<string*> range ) const {
        for( string* p=range.begin(); p!=range.end(); ++p ) {
            StringTable::accessor a;
            table.insert( a, *p );
            a->second += 1;
        }
    }
};
const size_t N = 1000000;
string Data[N];
void CountOccurrences() {
// Construct empty table.
StringTable table;

// Put occurrences into the table
parallel_for( blocked_range<string*>( Data, Data+N, 1000 ),
                Tally(table) );

// Display the occurrences
for( StringTable::iterator i=table.begin(); i!=table.end(); ++i )
    printf("%s %d\n",i->first.c_str(),i->second);
}

concurrenthashmap 扮演一个类型 std::pair<constKey,T> 元素的容器,当访问一个容器元素时,你对更新它或者读取它感兴趣,模板类concurrent_hash_map支持这2个目的,对应类accessor和const_accessor,其担当智能指针,accessor表示更新(write)访问,一旦它指向一个元素,所有其他尝试寻找这个表的key都会被阻止,直到accessor被完成。const_accessors是类似的,除了只表示读访问,多const_accessors能同时指向相同的元素,在频繁的读但是很少更新的情况下,这个特点极大的改善并行情形。

方法find和insert采用accessor或者const_accessor作为一个参数,告诉concurrent_hash_map是否你要求更新或者只读访问,一旦这个方法返回,直到访问结束,accessor或者const_accessor才会被销毁,因为对元素的访问阻止其他线程,所以尽可能的缩减accessor或者const_accessor生命周期,为了这么做,我们在内部块中声明它,尽可能在块结束前释放这个accessor,下面的例子是重写循环体,使用release结束accessor的生命周期:

StringTable accessor a;
for( string* p=range.begin(); p!=range.end(); ++p ) {
    table.insert( a, *p );
    a->second += 1;
    a.release();
}

方法remove(key)也能同时操作,它隐式请求写访问,因此,在删除这个Key之前,它等待其他现存key上的访问结束。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值