简体   繁体   中英

concurrent_vector invalid data

using : VC++ 2013

concurrency::concurrent_vector<datanode*> dtnodelst

Occasionally when I do dtnodelst->at(i) .... I am getting an invalid address (0XCDCD.. ofc) which shouldn't be the case cause after I do push back, I never delete or remove any of the itms ( even if I delete it should have returned the deleted old address... but I am not ever deleting so that is not even the case )

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

any ideas on what might be happening ?

ps I am using windows thread pool. some times .. I can do 8million inserts and find and everything goes fine .... but sometimes even 200 inserts and finds will fail. I am kind of lost. any help would be awesomely appreciated!!

thanks and best regards

actual code as an fyi

ps am I missing something or is it pain in the ass to past code with proper formatting ? I remember it being auto align before ... -_-

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

The problem is using of concurrent_vector::size() which is not fully thread-safe as you can get reference to not yet constructed elements (where memory contains garbage). Microsoft PPL library (which provides it in concurrency:: namespace) uses Intel TBB implementation of concurrent_vector and TBB Reference says:

size_type size() const | Returns : Number of elements in the vector. The result may include elements that are allocated but still under construction by concurrent calls to any of the growth methods.

Please see my blog for more explanation and possible solutions.

In TBB, the most reasonable solution is to use tbb::zero_allocator as underlying allocator of concurrent_vector in order to fill newly allocated memory with zeroes before size() will count it too.

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

Then, the condition if (nd) will filter out not-yet-ready elements.

volatile is no substitute for atomic<T> . Do not use volatile in some attempt to provide synchronization.

The whole idea of your find call doesn't make sense in a concurrent context. As soon as the function iterates over one value, it could be mutated by another thread to be the value you're looking for. Or it could be the value you want, but mutated to be some other value. Or as soon as it returns false , the value you're seeking is added. The return value of such a function would be totally meaningless. size() has all the same problems, which is a good part of why your implementation would never work.

Inspecting the state of concurrent data structures is a very bad idea, because the information becomes invalid the moment you have it. You should design operations that do not require knowing the state of the structure to execute correctly, or, block all mutations whilst you operate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM