gpt4 book ai didi

c++ - 锁定 shared_ptr

转载 作者:可可西里 更新时间:2023-11-01 15:20:29 25 4
gpt4 key购买 nike

我有一个共享对象需要发送到系统 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 对象布局中,另外一个 weak_ptr在基类中 enable_shared_from_this .

  • 正如我在评论中提到的,访问 lock()unlock()同时是不安全的。

  • 最糟糕的是这个解决方案只能支持lock()unlock() 的电话之前一次.如果同一个对象要用于多个系统 API 调用,则必须实现额外的引用计数。

如果我们有另一个 enable_lockable_shared_from_this类(class)会很棒:

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` 模板类派生的东西。

关于c++ - 锁定 shared_ptr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8073086/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com