неверные данные concurrent_vector

использование: VC ++ 2013

concurrency::concurrent_vector<datanode*> dtnodelst

Иногда, когда я делаю dtnodelst->at(i) …. Я получаю неверный адрес (0XCDCD .. ofc)
что не должно быть причиной после того, как я делаю назад, я никогда не удаляю и не удаляю ни одного из них (даже если я удаляю его, он должен был вернуть удаленный старый адрес … но я никогда не удаляю, так что это даже не дело)

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

есть идеи о том, что может происходить?

постскриптум Я использую пул потоков Windows. несколько раз .. Я могу сделать 8 миллионов вставок и найти, и все идет хорошо …. но иногда даже 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;
}

1

Решение

Проблема заключается в использовании 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) отфильтрует еще не готовые элементы.

3

Другие решения

volatile не заменит atomic<T>, Не использовать volatile в некоторых попытках обеспечить синхронизацию.

Целый идея вашей find вызов не имеет смысла в параллельном контексте. Как только функция выполняет итерации по одному значению, она может быть видоизменена другим потоком для получения значения, которое вы ищете. Или это может быть значение, которое вы хотите, но видоизмененный, чтобы быть другим значением. Или как только он вернется false, значение, которое вы ищете, добавляется. Возвращаемое значение такой функции было бы совершенно бессмысленным. size() имеет все те же проблемы, что является хорошей частью того, почему ваша реализация никогда не будет работать.

Проверка состояния параллельных структур данных — очень плохая идея, потому что информация становится недействительной в тот момент, когда она у вас есть. Вы должны разрабатывать операции, которые не требуют знания состояния структуры для правильного выполнения, или блокировать все мутации во время работы.

-1