c++ - 保存对 tbb::concurrent_unordered_map 项目的引用是否安全?
问题描述
我遇到了一些我继承的现有代码,它查找并存储存储在 tbb::concurrent_unordered_map 中的结构的引用。我知道如果它是一个迭代器,它会是安全的,但对实际对象的引用似乎很可疑。
该代码不断将新项目插入 tbb::concurrent_unordered_map。插入是否可以不更改 tbb 映射中包含的项目的物理位置,这会使存储的引用指向错误的位置,就像 std::map 一样?
tbb 文档指出:
“像 std::list 一样,新项目的插入不会使任何迭代器无效,也不会更改映射中已有项目的顺序。插入和遍历可能是并发的。”
我知道对于 std::list 插入新项目时位置不会改变,但是因为 concurrent_unordered_map 文档只讨论了订单,我担心这并没有明确说明它可以移动位置。
下面是一些伪代码,演示了我遇到的代码的概念。
struct MyStruct {
int i;
int j;
};
//some other thread will insert items into myMap
tbb::concurrent_unordered_map <int, MyStruct> myMap;
MyStruct& getMyStruct (int id)
{
auto itr=myMap.find (id);
if (itr!=myMap.end ()) return itr->second;
static MyStruct dummy {1,2};
return dummy;
}
class MyClass {
public:
MyClass (int id)
:m_myStruct {getMyStruct (id)}
{
}
void DoSomething () {
std::cout<<m_myStruct.i<<std::endl;
}
protected:
MyStruct& m_myStruct; //reference to an item held into a tbb::concurrent_unordered_map
};
这段代码已经以相对较高的频率运行了一年多,这似乎表明它是安全的,但我想确定保持对 tbb::concurrent_unordered_map 中包含的项目的引用是安全的.
重写代码需要做很多工作,所以如果可以保持原样,我宁愿不必这样做。
谢谢,
保罗
解决方案
如果您非常担心进入未完全记录的行为的灰色区域,为什么不存储和使用迭代器呢?一个问题是它的大小(运行它):
#include <tbb/tbb.h>
int main() {
tbb::concurrent_unordered_map<int, int> m;
printf("Size of iterator: %lu\n", sizeof(m.begin()));
}
这是因为除了指向元素的指针之外,迭代器还有指向它所属容器的指针。没有指针列表或任何其他结构来注册用户创建的所有迭代器,因此容器无法更新迭代器以指向不同的地址(这在并行程序中尤其棘手)。无论如何,这样的重定位会导致额外的用户可见调用键/值类型的移动/复制构造函数,因此将被记录。文档中没有这样的警告,添加它会导致向后不兼容的更改,这为您提供了一种间接保证,即您可以安全地保留指向项目的指针而不是使用迭代器。
推荐阅读
- c++ - Qt 中的 iOS 通知
- powershell - Azure devops - 更新 json 文件 - powershell 脚本
- c++ - 有没有办法在 C++ 中初始化这样的 3D 数组?
- c - 为什么 getpwnam 返回的结构的 pw_passwd 字段不包含我的密码哈希?
- c# - 使用一个脚本获得 3 个不同的值
- c# - 如何禁用特定行并防止在 Xamarin 数据网格中单击?
- reactjs - React Grid 上的弹出图像
- python - Python 使用 pytest_mock 在一个函数中模拟多个查询
- powershell - 如何使用 PowerShell 在 GUI 表单中处理标签大小和位置?
- c# - .Net HttpClient - 403:请启用cookies