Потоки общей модели с указателями

У меня есть вектор указателей на объекты, созданные с помощью new. Несколько потоков получают безопасный доступ к этому вектору с помощью различных операций получения/набора. Однако поток может удалить один из объектов, и в этом случае указатель другого потока на объект больше недействителен. Как метод может узнать, действителен ли указатель? Варианты 1 и 2 действительно работают хорошо. Я не знаю, как они будут масштабироваться. Каков наилучший подход? Есть портативная версия 3?

Проверка работоспособности указателя на примеры:

1. Используйте целые числа вместо указателей. Хэш (std::map) проверяет, действителен ли указатель. Публичные методы выглядят так:

get(size_t iKey)
{
   if((it = mMap.find(iKey)) != mMap.end())
   {
       TMyType * pMyType = it->second;
       // do something with pMyType
   }
}

2. Иметь вектор shared_ptr. Каждый поток пытается вызвать функцию lock() для своего weak_ptr. Если возвращенный shared_ptr равен нулю, мы знаем, что кто-то удалил его, пока мы ждали. Публичные методы выглядят так:

get(boost::weak_ptr<TMyType> pMyType)
{
    boost::shared_ptr<TMyType> pGOOD = pMyType.lock();
    if (pGOOD  != NULL)
    {
         // Do something with pGOOD
    }
} 

3. Проверять наличие нулей в простых необработанных указателях? Это возможно?

get(TMyType * pMyType)
{
    if(pMyType != NULL){ //do something }
}

person pcunite    schedule 05.03.2011    source источник


Ответы (1)


№3 не подойдет. Удаление указателя и присвоение ему значения NULL не влияет на другие указатели, указывающие на тот же объект. Вы ничего не можете сделать с необработанными указателями, чтобы определить, удален ли объект.

#1 фактически является указателем на указатель. Если вы всегда обращаетесь к нему через этот указатель и можете его заблокировать. Если нет, что произойдет, если он будет удален в другом потоке после того, как вы его успешно получите?

№ 2 — это стандартная реализация такого рода идей, и шаблон используется во многих библиотеках. Блокировка ручки, получение указателя. Если вы его получите, используйте его. Если нет, то его нет.

person Lou Franco    schedule 05.03.2011
comment
Насчет №3, да, я должен был это знать... Что касается №1, то это число, а не указатель. Поток вызывает get() и получает число, через час он вызывает set(1234), и метод проверяет, существует ли еще 1234 на карте. Доступ к карте осуществляется только через потокобезопасные вызовы, поэтому она работает хорошо. Когда другой поток что-то удаляет, следующий сериализованный поток обнаруживает, что его ключ больше не действителен. Но постоянный поиск в хэше может плохо масштабироваться. - person pcunite; 05.03.2011
comment
И по аналогии с № 1 номер № 3 будет работать, если вместо этого вы сделаете его указателем на указатель. - person stefan; 05.03.2011
comment
Так что, если я сделаю указатель на указатель, он будет работать? Покажи мне, что ты говоришь, если не возражаешь. - person pcunite; 05.03.2011
comment
@pcunite, хорошо, если вы (правильно) используете указатель на указатель, вы можете обнулить целевой указатель и проверить *P == NULL. - person stefan; 05.03.2011
comment
@stefan, ну, когда для указателя вызывается удаление, он не знает, кто его наблюдает, поэтому позже, когда этот адрес памяти снова используется, двойной указатель будет думать, что все в порядке. Мне нужен объект, которым на самом деле является weak_ptr, просто класс, наблюдающий за другим классом. Я думаю ... - person pcunite; 05.03.2011
comment
Хорошо, как насчет карты указателей на указатели? Будет ли карта быстро находить другой указатель? Когда он не находит его, он может вернуть NULL, что было бы гладко. Я предполагаю, что std::map‹int,int› будет таким же, как ‹pointer, pointer›? - person pcunite; 05.03.2011
comment
Проблема с картами int to pointer, указателем на указатели и другими подобными схемами заключается в том, что время, которое вы получаете, соответствует времени, когда вы его используете. За это время его можно было удалить. Замок в №2 — стандартное решение проблемы. Вы блокируете, чтобы получить реальный указатель. Никто не может удалить, если дескриптор (указатель на указатель) не разблокирован. Блокировка увеличивает счет, разблокировка уменьшает. - person Lou Franco; 05.03.2011
comment
@Lou Franco, - часть 1. Я ценю вашу помощь, могу ли я еще раз поспорить о картах :), я только учусь здесь, у меня есть решение, работающее со weak_ptr, так что я это понимаю ... Хорошо, причина map не является проблемой, потому что все потоки сериализованы, когда вызывается поиск на карте, это единственный поток, который имеет доступ к общему местоположению. Он получит указатель или будет безопасно получать NULL каждый раз. Удаление вызывается Моделью, когда она считает нужным. - person pcunite; 05.03.2011
comment
@Lou Franco, - часть 2. Слабый_ptr теперь крут, потому что, когда объект вырывается из-под вас, он не позволит вам получить shared_ptr. То же самое с таблицей поиска карты. Имеет ли это смысл? Функция lock() для weak_ptr не гарантирует, что объект не был удален явным образом, а только то, что счетчик ссылок не удалит его автоматически. Другой сериализованный поток может вызвать reset() в любое время. Я правильно понимаю? - person pcunite; 05.03.2011
comment
@Lou Franco, часть 3. Чтобы уточнить, у меня есть класс данных, доступный для многих потоков, которые добавляют или удаляют объекты. Таким образом, каждый раз, когда потоку разрешается сериализованный доступ, он проверяет, действителен ли его предыдущий указатель. Карта или weak_ptr хорошо подходят для этого с 5 000 000 элементов. Скорость кажется одинаковой... проверка блокировки() или выполнение map.find() занимает одинаковое количество времени. - person pcunite; 05.03.2011
comment
Лу дал тебе правильный ответ. Часть 1: ваш код будет трудно читать, если вы реализуете его таким образом. Хороший код должен быть простым для понимания. Часть 2: стандартный подход к типовой задаче. Используй это. Часть 3: Рано или поздно вы получите множество багов с оборванными указателями. Даже если вы думаете, что это работает для вас сейчас. - person Eugene; 05.03.2011
comment
Я неправильно это объяснил. Но да, @Lou прав. На самом деле происходит то, что каждый поток имеет указатель на объект (забудьте на данный момент о векторе), и он использует его как ключ много часов спустя. Когда он получает доступ к кешу модели/базы данных, поток хочет выполнять работу с использованием этого ключа, конечно, теперь он больше недействителен. Вот почему использование карты работает, но я не хотел каждый раз искать, поэтому работает weak_ptr. Указатель — это самый быстрый способ вернуться к этому объекту. - person pcunite; 05.03.2011