Блокировка shared_ptr

У меня есть общий объект, который нужно отправить в системный API и извлечь его позже. Системный API получает только void *. Я не могу использовать shared_ptr :: get (), потому что он не увеличивает счетчик ссылок и может быть выпущен другими потоками перед извлечением из системного API. Отправка нового shared_ptr * будет работать, но требует дополнительного выделения кучи.

Один из способов сделать это - разрешить объекту, производному от enable_shared_from_this. Однако, поскольку этот шаблон класса владеет только weak_ptr, этого недостаточно для предотвращения освобождения объекта.

Итак, мое решение выглядит следующим образом:

class MyClass:public enable_shared_from_this<MyClass> {
private:
    shared_ptr<MyClass> m_this;
public:
    void *lock(){
        m_this=shared_from_this();
        return this;
    }
    static shared_ptr<MyClass> unlock(void *p){
        auto pthis = static_cast<MyClass *>(p);
        return move(pthis->m_this);
    }
/* ... */
}

/* ... */
autp pobj = make_shared<MyObject>(...);
/* ... */
system_api_send_obj(pobj->lock());
/* ... */
auto punlocked = MyClass::unlock(system_api_reveive_obj());

Есть ли более простой способ сделать это?

Обратной стороной этого решения:

  • требуется дополнительный shared_ptr в макете объекта MyClass в дополнение к weak_ptr в базовом классе enable_shared_from_this .

  • Как я уже упоминал в комментариях, одновременный доступ к lock () и unlock () НЕ является безопасным.

  • Хуже всего то, что это решение может поддерживать lock () только один раз перед вызовом unlock () . Если один и тот же объект должен использоваться для нескольких вызовов системного API, необходимо реализовать дополнительный подсчет ссылок.

Если у нас есть еще один класс enable_lockable_shared_from_this , он будет отличным:

class MyClass:public enable_lockable_shared_from_this<MyClass> {
/* ... */
}

/* ... */
autp pobj = make_shared<MyObject>(...);
/* ... */
system_api_send_obj(pobj.lock());
/* ... */
auto punlocked = unlock_shared<MyClass>(system_api_reveive_obj());

И реализация enable_lockable_shared_from_this аналогична enable_shared_from_this] реализует lock () и вспомогательную функцию unlock_shared . Вызов этих функций только явно увеличивает и уменьшает use_count (). Это будет идеальным решением, потому что:

  • Это устраняет дополнительные затраты на пространство.

  • Он повторно использует возможности, существующие для shared_ptr, чтобы гарантировать безопасность параллелизма.

  • Лучшее в этом решении - то, что оно поддерживает множественные вызовы lock () без проблем.

Однако единственный самый большой недостаток: в данный момент он недоступен!

ОБНОВЛЕНИЕ:

По крайней мере, два ответа на этот вопрос связаны с контейнером указателей.Пожалуйста, сравните эти решения со следующим:

class MyClass:public enable_shared_from_this<MyClass> {
private:
    shared_ptr<MyClass> m_this;
    mutex this_lock; //not necessory for single threading environment
    int lock_count;
public:
    void *lock(){
        lock_guard lck(this_lock); //not necessory for single threading environment
        if(!lock_count==0)
            m_this=shared_from_this();
        return this;
    }
    static shared_ptr<MyClass> unlock(void *p){
        lock_guard lck(this_lock); //not necessory for single threading environment
        auto pthis = static_cast<MyClass *>(p);
        if(--lock_count>0)
            return pthis->m_this;
        else {
            lock_count=0;
            return move(pthis->m_this); //returns nullptr if not previously locked
        }
    }
/* ... */
}

/* ... */
autp pobj = make_shared<MyObject>(...);
/* ... */
system_api_send_obj(pobj->lock());
/* ... */
auto punlocked = MyClass::unlock(system_api_reveive_obj());

Это абсолютно игра O (1) против O (n) (пространство; время - O (log (n)) или аналогичная, но абсолютно большая, чем O (1)).

11
задан Earth Engine 21 November 2011 в 21:42
поделиться