3

使用:VC++ 2013

concurrency::concurrent_vector<datanode*> dtnodelst

有时当我这样做时dtnodelst->at(i)....我得到一个无效的地址(0XCDCD.. ofc),这不应该是因为在我推回之后,我从不删除或删除任何项目(即使我删除它应该已返回已删除的旧地址...但我从未删除过,所以情况并非如此)

dtnodelst itm = new dtnodelst ();
....
dtnodelst->push_back(itm);

关于可能发生的事情有什么想法吗?

ps 我正在使用 Windows 线程池。有时..我可以进行 800 万次插入和查找,一切顺利....但有时即使 200 次插入和查找也会失败。我有点迷路了。任何帮助将不胜感激!

谢谢和最好的问候

实际代码仅供参考

ps 我是否遗漏了某些内容,或者过去的代码格式是否正确?我记得它之前是自动对齐的...... -_-

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;
}
4

2 回答 2

5

问题在于使用concurrent_vector::size()它不是完全线程安全的,因为您可以获得对尚未构造的元素的引用(其中内存包含垃圾)。Microsoft PPL 库(在命名空间中提供它concurrency::)使用 Intel TBB 实现concurrent_vector和 TBB参考说:

size_type size() const| 返回: 向量中的元素数。结果可能包括通过并发调用任何增长方法分配但仍在构建中的元素。

请参阅我的博客以获取更多解释和可能的解决方案。

在 TBB 中,最合理的解决方案是tbb::zero_allocator用作底层分配器,concurrent_vector以便在 size() 也计算它之前用零填充新分配的内存。

concurrent_vector<datanode*, tbb::zero_allocator<datanode*> > lst;

然后,条件if (nd)将过滤掉尚未准备好的元素。

于 2014-08-18T16:42:52.500 回答
-1

volatile不可替代atomic<T>。不要volatile在某些尝试中使用来提供同步。

您的通话的整个想法find在并发上下文中没有意义。一旦函数迭代一个值,它可能会被另一个线程改变为您正在寻找的值。或者它可能是您想要的值,但变异为其他值。或者一旦它返回false,你正在寻找的价值就会被添加。这样一个函数的返回值是完全没有意义的。size()有所有相同的问题,这是为什么您的实施永远不会工作的一个很好的部分。

检查并发数据结构的状态是一个非常糟糕的主意,因为信息在你拥有它的那一刻就变得无效。您应该设计不需要知道结构状态即可正确执行的操作,或者在您操作时阻止所有突变。

于 2014-08-18T17:06:57.847 回答