使用:VC ++ 2013
concurrency::concurrent_vector<datanode*> dtnodelst
偶尔我做dtnodelst->at(i)
....我收到的地址无效(0XCDCD .. ofc)
这不应该是因为我推回后的情况,我永远不会删除或删除任何itms(即使我删除它应该已经返回已删除的旧地址...但我不会删除所以,甚至不是案例)
dtnodelst itm = new dtnodelst ();
....
dtnodelst->push_back(itm);
关于可能发生的事情的任何想法?
P.S。我正在使用Windows线程池。有时候..我可以做800万次插入并找到并且一切都很好....但有时甚至200次插入和发现都会失败。我有点迷茫。任何帮助都会非常赞赏!!
感谢和最好的问候
P.S。我是否遗漏了某些东西,或者过去的代码是否因为格式正确而感到痛苦?我记得它在...之前自动对齐... -_-
struct datanode {
volatile int nodeval;
T val;
};
concurrency::concurrent_vector<datanode*> lst
inline T find(UINT32 key)
{
for (int i = 0; i < lst->size(); i++)
{
datanode* nd = lst->at(i);
//nd is invalid sometimes
if (nd)
if (nd->nodeval == key)
{
return (nd->val);
}
}
return NULL;
}
inline T insert_nonunique(UINT32 key, T val){
datanode* itm = new datanode();
itm->val = val;
itm->nodeval = key;
lst->push_back(itm);
_updated(lst);
return val;
}
答案 0 :(得分:3)
问题是使用了concurrent_vector::size()
,它不是完全线程安全的,因为你可以引用尚未构造的元素(内存中包含垃圾)。 Microsoft PPL库(在concurrency::
命名空间中提供)使用concurrent_vector
和TBB Reference的英特尔TBB实现:
size_type size() const
| 返回:向量中的元素数。结果可能包括通过并发调用任何增长方法而分配但仍在构建的元素。
有关更多说明和可能的解决方案,请参阅my blog。
在TBB中,最合理的解决方案是使用tbb::zero_allocator
作为concurrent_vector
的基础分配器,以便在size()计数之前用新零填充新分配的内存。
concurrent_vector<datanode*, tbb::zero_allocator<datanode*> > lst;
然后,条件if (nd)
将过滤掉尚未准备好的元素。
答案 1 :(得分:-1)
volatile
不能代替atomic<T>
。在尝试提供同步时不要使用volatile
。
find
调用的整个想法在并发上下文中没有意义。一旦函数迭代了一个值,它就可以被另一个线程变异为你正在寻找的值。或者它可能是您想要的值,但是变异为其他值。或者只要它返回false
,就会添加您要搜索的值。这种功能的返回值完全没有意义。 size()
具有所有相同的问题,这是您的实施永远不会起作用的一个很好的部分。
检查并发数据结构的状态是一个非常糟糕的主意,因为信息在您拥有它时就会变得无效。您应该设计不需要知道结构状态的操作,以便在操作时阻止所有突变。