Повышение общих указателей C : общий указатель не может освободить ресурс при выпуске

#c #pointers #boost #shared

#c #указатели #повышение #общий

Вопрос:

Я столкнулся с проблемой, когда я не могу избавиться от последнего общего указателя, и мне это действительно нужно.

Итак, у меня есть менеджер и несколько рабочих потоков. Менеджер хранит коллекцию общих указателей на разные ресурсы. Работник может запросить у менеджера общий указатель на ресурс. Всегда будет 1 или более рабочих с общим указателем на ресурс. Моя конечная цель состоит в том, чтобы, когда все рабочие закончили с ресурсом, ресурс был удален. Однако в этой схеме менеджер всегда поддерживает общий указатель на ресурс, поэтому, даже если на общем указателе нет рабочих, ресурс не будет удален b / c счетчик ссылок всегда должен быть не менее 1, поскольку менеджер висит на нем. Мне нужно, чтобы менеджер зависал на общем указателе на ссылку, чтобы, если какой-либо работник попросит общий указатель, менеджер сможет его предоставить.


редактировать: когда ресурс создается, у работника он уже есть. Таким образом, при его создании его количество ссылок должно быть равно двум (оно есть у менеджера, и оно есть у одного работника). Когда счетчик ссылок достигает единицы (он есть только у менеджера), я бы хотел, чтобы он был удален. Если ресурс уже был удален и его ищет рабочий, ресурс должен быть воссоздан заново.


правка2: некоторый код:

 SomeSharedPointer Manager::getResource(String unique_id) 
{ // if unique id exists, return its mapped shared pointer, if unique id doesn't exist, create the resource, assign it a shared pointer, and stick it in the map 
}


class Worker
{
    SomeSharedPointer my_sp;

    Worker()
    {
       String someUniqueId = "http://blah.com"
       my_sp = Manager::getResource(someUniqueId);
       // do some work on the resource
    }

    ~Worker()
    {
        my_sp.reset(); // done with resource
    }
}
  

Комментарии:

1. Вам необходимо предоставить некоторый исходный код, чтобы продемонстрировать, как вы работаете с shared_ptr s.

2. A. см. weak_ptr B. вы не должны удалять общие указатели. Объекты, на которые указывает общий указатель, будут удалены

3. @sehe: да, я не удаляю сам общий указатель.

Ответ №1:

Почему менеджер хранит shared_ptr (строгую ссылку) на объект, если ему не нужно сохранять контроль, а только передавать его? Не видя вашего кода, кажется, что менеджер удерживает a weak_ptr , а затем передает его работникам, которые фиксируют его в a shared_ptr на своем конце. Это позволит менеджеру передавать ссылки, не владея ни одной из своих собственных.

 class Worker
{
    SomeSharedPointer my_sp;

    Worker()
    {
        String someUniqueId = "http://blah.com"
        weak_ptr wp = Manager::getResource(someUniqueId);
        my_sp = wp.lock();

        // do some work on the resource
    }

    ~Worker()
    {
        //my_sp.reset(); // handled automatically, as part of how shared pointers work
    }
}
  

Если рабочий завершит и освободит ресурс, он будет уничтожен, и менеджер больше не сможет раздавать ссылки (которые можно протестировать getResource и перезагрузить). Это кажется не совсем оптимальным, но является частью вашего дизайна, поэтому он должен работать так хорошо.

Редактировать: вы также могли бы getResource вернуть общий указатель и попросить менеджера удерживать слабый указатель, попытаться заблокировать, выполнить внутреннюю проверку / перезагрузку, а затем вернуть общий указатель. Поскольку weak_ptr s не могут быть созданы напрямую, это может работать несколько лучше.

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

Комментарии:

1. не зная слишком много о слабых указателях, это звучит как то, что мне нужно — тип указателя, который не имеет права собственности и не влияет на количество ссылок…

2. Это и есть слабые указатели, они сохраняют счетчик ссылок и могут предоставлять общие указатели (после проверки), но сами не владеют объектом и поэтому не учитываются как ссылки.

3. Что вы имели в виду в своем редактировании, что оно кажется не совсем оптимальным в том виде, в каком я его получил? Чтобы объяснить дальше, я удаляю ресурсы, когда рабочие с этим закончили, потому что это может быть случай, когда рабочие не используют ресурс в течение длительных периодов времени. Поэтому я думаю, что я бы хотел удалить ресурс до тех пор, пока другой работник не запросит его снова. Чтобы сделать пример более конкретным, я открываю сетевые подключения для этих работников. Я не хочу хранить около тонны открытых подключений, когда их не используют работники.

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

Ответ №2:

Используйте слабый указатель в диспетчере и общий указатель в рабочих, когда рабочий приходит с запросом указателя, создайте общий указатель, используя метод блокировки.

как в boost::shared_ptr fptr = weakfoo.lock();

если общий указатель пуст, указатель либо был выпущен последним работником, либо еще не создан и нуждается в создании

Я бы определенно избегал любых решений, связанных с просмотром количества ссылок… последует только боль 🙂

Ответ №3:

Я думаю, что ключевым является следующее:

Мне нужно, чтобы менеджер зависал на общем указателе на ссылку, чтобы, если какой-либо работник попросит общий указатель, менеджер сможет его предоставить.

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