【问题标题】:concurrent_vector invalid dataconcurrent_vector 无效数据
【发布时间】:2014-02-16 06:35:43
【问题描述】:

使用:VC++ 2013

concurrency::concurrent_vector<datanode*> dtnodelst

偶尔当我做dtnodelst-&gt;at(i) .... 我得到一个无效的地址 (0XCDCD.. ofc) 这不应该是这种情况,因为在我推回之后,我从不删除或删除任何项目(即使我删除它也应该返回已删除的旧地址......但我从来没有删除,所以这甚至不是案例)

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

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

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

感谢和问候

实际代码仅供参考

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

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

【问题讨论】:

    标签: c++ multithreading visual-c++ concurrency concurrent-vector


    【解决方案1】:

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

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

    请参阅my blog 了解更多解释和可能的解决方案。

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

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

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

    【讨论】:

    【解决方案2】:

    volatile 不能替代 atomic&lt;T&gt;。不要使用volatile 来提供同步。

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

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

    【讨论】:

    • volatile 的潜在误用在这里不起作用,因为据我所知,指针 datanode* nd 的地址无效——我的回答就是这种情况。请删除downvote
    • 此外,说这种方法不好是不公平的。例如,用户可能想要创建并发快照,或者可能想要手动同步对元素的访问 - 例如 tbb:: 和 ppl::concurrent_unordered_map。
    猜你喜欢
    • 1970-01-01
    • 2011-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多