c – 锁定一个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之外. 如果我们有另一个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().这将是理想的解决方案,因为: >消除额外的空间成本 然而,唯一最大的缺点是:目前不可用! 更新: 这个问题的至少两个答案涉及一个指针的容器.请将这些解决方案与以下内容进行比较: 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`模板类派生的东西. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |