加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 锁定一个shared_ptr

发布时间:2020-12-16 05:42:14 所属栏目:百科 来源:网络整理
导读:我有一个共享对象,需要发送到一个系统API,并在以后解压缩.系统API只接收void *.我不能使用shared_ptr :: get(),因为它不会增加引用计数,并且可以在从系统API提取之前被其他线程释放.发送一个新的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>在MyClass对象布局中,除了在基类enable_shared_from_this中的weak_ptr之外.
>正如我在评论中提到的,同时访问lock()和unlock()是不安全的.
最糟糕的是,这个解决方案只能在调用unlock()之前支持一次lock().如果同一个对象用于多个系统API调用,则必须执行额外的引用计数.

如果我们有另一个enable_lockable_shared_from_this类,那将是greate:

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)vs O(n)(空间;时间是O(log(n))或类似的,但绝对大于O(1))游戏.

解决方法

我现在有一个想法如下:
template<typename T>
struct locker_helper{
    typedef shared_ptr<T> p_t;
    typedef typename aligned_storage<sizeof(p_t),alignment_of<p_t>::value>::type s_t;
};
template<typename T> void lock_shared(const shared_ptr<T> &p){
    typename locker_helper<T>::s_t value;
    new (&value)shared_ptr<T>(p);
}
template<typename T> void unlock_shared(const shared_ptr<T> &p){
    typename locker_helper<T>::s_t value
        = *reinterpret_cast<const typename locker_helper<T>::s_t *const>(&p);
    reinterpret_cast<shared_ptr<T> *>(&value)->~shared_ptr<T>();
}


template<typename T>
void print_use_count(string s,const shared_ptr<T> &p){
    cout<<s<<p.use_count()<<endl;
}

int main(int argc,char **argv){
    auto pi = make_shared<int>(10);
    auto s = "pi use_count()=";
    print_use_count(s,pi); //pi use_count()=1
    lock_shared(pi);
    print_use_count(s,pi);//pi use_count()=2
    unlock_shared(pi);
    print_use_count(s,pi);//pi use_count()=1
}

然后我们可以实现原来的例子如下:

class MyClass:public enable_shared_from_this { /*...*/ };

/* ... */
auto pobj = make_shared<MyClass>(...);
/* ... */
lock_shared(pobj);
system_api_send_obj(pobj.get());
/* ... */
auto preceived = 
    static_cast<MyClass *>(system_api_reveive_obj())->shared_from_this();
unlock_shared(preceived);

这个想法很容易实现一个enable_lockable_shared_from_this.然而,以上是更通用的,允许控制不是从enable_lockable_from_this`模板类派生的东西.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读