一种方法是让来自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`模板类派生的东西.