tbb::concurrent_hash_map<K,V>
在英特尔线程构建模块(TBB)中寻找要使用的示例代码。
我可以插入,但似乎无法读回值。
该官员Intel的文档似乎有点欠缺的示例代码侧。
最好的文档在Voss的“ Pro TBB:带有线程构建块的C ++并行编程”中。免费下载此书(属于公共领域)。
忽略英特尔文档。它们本质上是功能签名的集合。
https://github.com/intel/tbb
要安装TBB,我用vcpkg是兼容Linux
,Windows
和Mac
。是的,vcpkg来自Microsoft,但是它是100%跨平台的,开源的,并且非常流行。
Linux:
./vcpkg search tbb # Find the package.
./vcpkg install tbb:x64-linux # Install the package.
视窗:
vcpkg search tbb # Find the package.
vcpkg install tbb:x64-windows # Install the package.
编译:
CMake
了gcc
。也可以下载源代码并将标头和库提取到源代码树中,这同样有效。
码。
#include "tbb/concurrent_hash_map.h" // For concurrent hash map.
tbb::concurrent_hash_map<int, string> dict;
typedef tbb::concurrent_hash_map<int, string>::accessor dictAccessor; // See notes on accessor below.
print(" - Insert key, method 1:\n");
dict.insert({1,"k1"});
print(" - 1: k1\n");
print(" - Insert key, method 2:\n");
dict.emplace(2,"k2");
print(" - 2: k2\n");
string result;
{
print(" - Read an existing key:\n");
dictAccessor accessor;
const auto isFound = dict.find(accessor, 2);
// The accessor functions as:
// (a) a fine-grained per-key lock (released when it goes out of scope).
// (b) a method to read the value.
// (c) a method to insert or update the value.
if (isFound == true) {
print(" - {}: {}\n", accessor->first, accessor->second);
}
}
{
print(" - Atomically insert or update a key:\n");
dictAccessor accessor;
const auto itemIsNew = dict.insert(accessor, 4);
// The accessor functions as:
// (a) a fine-grained per-key lock (released when it goes out of scope).
// (b) a method to read the value.
// (c) a method to insert or update the value.
if (itemIsNew == true) {
print(" - Insert.\n");
accessor->second = "k4";
}
else {
print(" - Update.\n");
accessor->second = accessor->second + "+update";
}
print(" - {}: {}\n", accessor->first, accessor->second);
}
{
print(" - Atomically insert or update a key:\n");
dictAccessor accessor;
const auto itemIsNew = dict.insert(accessor, 4);
// The accessor functions as:
// (a) a fine-grained per-key lock which is released when it goes out of scope.
// (b) a method to read the value.
// (c) a method to insert or update the value.
if (itemIsNew == true) {
print(" - Insert.\n");
accessor->second = "k4";
}
else {
print(" - Update.\n");
accessor->second = accessor->second + "+update";
}
print(" - {}: {}\n", accessor->first, accessor->second);
}
{
print(" - Read the final state of the key:\n");
dictAccessor accessor;
const auto isFound = dict.find(accessor, 4);
print(" - {}: {}\n", accessor->first, accessor->second);
}
打印使用{fmtlib}进行打印;可以替换为cout <<
。
输出:
- Insert key, method 1:
- 1: k1
- Insert key, method 2:
- 2: k2
- Read an existing key:
- 2: k2
- Atomically insert or update a key:
- Insert.
- 4: k4
- Atomically insert or update a key:
- Update.
- 4: k4+update
- Read the final state of the key:
- 4: k4+update
std::unordered_map
。它具有更标准的API,并且在许多情况下是线程安全的,请参阅:unordered_map线程安全。如果可能的话,建议使用它,因为它具有更简单的API。concurrent_unordered_map
来自Intel TBB的。本质上是同一件事,一个键/值映射。但是,它年代久远,级别低得多,并且使用起来更困难。必须提供一个哈希器,一个相等运算符和一个分配器。即使在正式的英特尔文档中,也没有任何示例代码。尽管有数月的不时尝试,但我从未成功。它可能已过时,因为在上述免费书中没有提及(仅涵盖concurrent_hash_map
)。不建议。实际上有两个访问器,一个是读锁,一个是写锁:
const_accessor
accessor
如果使用find
,则使用const_accessor
read锁。如果使用insert
或erase
,则使用accessor
写锁(即它将等待所有读取完成,并阻止其他读取直到完成)。
这实际上等效于读取器/写入器锁,但仅在字典中使用单个字典键,而不是整个字典。
学习曲线的最后一部分:对于键写,直到访问器超出范围,什么都不会发生。因此,可以使用CAS(比较和交换)来保留不超过几个机器指令的任何锁。
将其与数据库进行比较,访问器的范围就像一个事务。当访问器超出范围时,整个事务将提交给哈希映射。
上面提到的免费书籍在的一章中有出色的性能提示concurrent_hash_map
。
此哈希图的API功能强大,但有些尴尬。但是,它支持在插入/更新时进行细粒度的每键锁定。使用CAS时,只有少数机器指令才能持有任何锁。这是其他任何语言都无法用任何语言提供的哈希图。std::unordered_map
为了简单起见,建议从此开始;只要两个线程不写入同一密钥,它就是线程安全的。如果需要极快的性能,则可以选择重构或在上面使用[]
访问器和编写兼容的包装insert_or_update()
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句