我正在尝试使用tbb的current_hash_map来提高应用程序的并发性能。阅读有关它的内容并根据我的应用程序将其实现,但是我看到崩溃了。
因此,我的应用程序是一个多线程应用程序,我要在其中存储对,键是char *,值是整数。伪代码看起来像这样:
在.h文件中,
typedef tbb::concurrent_hash_map<const void*, unsigned, Hasher> tbb_concurrent_hash;
tbb_concurrent_hash concurrent_hash_table;
tbb_concurrent_hash::accessor write_lock;
tbb_concurrent_hash::const_accessor read_lock;
在.c文件中,
void storeName(const char * name) {
int id=0;
// This creates a pair object of name and index
std::pair object(name, 0);
// read_lock is a const accessor for reading. This find function searches for char* in the table and if not found, create a write_lock.
bool found = concurrent_hash_table.find(read_lock, name);
if (found == FALSE) {
concurrent_hash_table.insert(write_lock, name);
// Get integer id somehow.
id = somefunction();
write_lock->second = id;
write_lock.release();
} else {
// if the name is found in the table then get the value and release it later
id = read_lock->second;
read_lock.release();
}
}
根据我的理解,我对实现很满意,但是正如我所说的,当find返回FALSE时会发生多次崩溃。崩溃也有互斥的痕迹。
答案 0 :(得分:4)
您的“锁”,即访问器在.h文件中声明为全局。因此,基本上,您将写入共享的scoped_lock实例...从逻辑上讲会导致数据争用。访问器就像一个或更简单的类std :: shared_ptr和std :: scoped_lock融合在一起-您的结果的指针和它所指向的数据的锁保护。您不想使用来自多个线程的一个全局指针。在您希望拥有该访问权限的范围内本地声明它们(并且您也不必调用.release()
)
另一个问题是find()和insert()之间的数据竞争。由于找不到任何内容,因此两个或多个线程可以决定必须插入。在这种情况下,第一个线程将插入新元素,而其他线程将返回现有元素,因为如果存在现有元素,则insert()充当find()。问题是您的代码无法解决这个问题。
我可以看到为什么您可能要使用const_accessor进行仔细检查,因为读取锁具有更高的可伸缩性。但是,相反,您可能想将bool insert( const_accessor& result, const value_type& value );
与读锁定(const_accessor)和value_type一起使用,而不是仅使用密钥,这将在添加新元素的情况下初始化整个对。