我遇到了一些继承的现有代码,它们查找并存储对存储在tbb :: concurrent_unordered_map中的结构的引用。我知道如果它是一个迭代器,那将是安全的,但是对实际对象的引用似乎很混乱。
代码不断将新项目插入tbb :: concurrent_unordered_map中。插入是否可以更改tbb映射中包含的项目的物理位置,从而使存储的引用指向与std :: map相同的错误位置?
tbb文档指出:
“类似于std :: list,插入新项目不会使任何内容无效 迭代器,也不更改地图中已有项目的顺序。插入 并且遍历可能是并发的。”
对于std :: list,我知道插入新项目时位置不会改变,但是因为currently_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。
重写代码需要大量工作,因此,如果可以保留原样,我宁愿不必这样做。
谢谢
保罗
答案 0 :(得分:0)
如果您非常担心进入未完全记录的行为的灰色区域,为什么不存储和使用迭代器呢?问题之一是它的大小(run it):
#include <tbb/tbb.h>
int main() {
tbb::concurrent_unordered_map<int, int> m;
printf("Size of iterator: %lu\n", sizeof(m.begin()));
}
这是因为除了pointer to the element之外,迭代器还具有它所属的pointer to the container。没有指针或任何其他结构的列表,这些列表注册了用户创建的所有迭代器,因此容器无法更新插入器以指向不同的地址(在并行程序中尤其棘手)。无论如何,这样的重定位将引起用户对键/值类型的移动/复制构造函数的其他可见调用,因此将被记录在案。文档中没有这样的警告,添加警告会导致向后不兼容的更改,这为您提供了一种间接保证,您可以安全地保留指向项目的指针,而不使用迭代器。