代码如下,shared_ptr怎么稍作改动能做到线程安全?

shilei_312 2014-09-16 11:10:30
请教,下面的shared_ptr怎么做到线程安全?(最好不用加锁,也不要像boost::shared_ptr那么复杂)

template <typename T> struct Deleter
{
typedef T value_type;
typedef void (*Type)(T*);

static void Delete(T* _obj_ptr)
{
delete _obj_ptr;
}
};

template<typename T, typename D = Deleter<T> >
class SharedPtr
{
public:
typedef T value_type;

SharedPtr();
SharedPtr(const SharedPtr& _ptr);
explicit SharedPtr(T* _ptr);

~SharedPtr();
SharedPtr& operator = (const SharedPtr& _ptr);

bool IsEmpty () const;
T& operator *() const;
T* operator->() const;

private:
T* holder_ptr;
long* ref_ptr;

void Release ();
void Swap(SharedPtr &_other);
};

//-------------------------------------------------------------------------
template<class T, class D>
inline bool Boi::SharedPtr<T, D>::IsEmpty() const
{
return !holder_ptr;
}
//-------------------------------------------------------------------------
template<class T, class D>
inline void Boi::SharedPtr<T, D>::Swap( SharedPtr<T, D> &_other )
{
std::swap(holder_ptr, _other.holder_ptr);
std::swap(ref_ptr, _other.ref_ptr);
}
//-------------------------------------------------------------------------
template<class T, class D>
inline void Boi::SharedPtr<T, D>::Release()
{
if (holder_ptr && ref_ptr && --*ref_ptr <= 0)
{
delete ref_ptr;
D::Delete(holder_ptr);
}
holder_ptr = NULL, ref_ptr = NULL;
}
//-------------------------------------------------------------------------
template<class T, class D>
inline T* Boi::SharedPtr<T, D>::operator->() const
{
return holder_ptr;
}
//-------------------------------------------------------------------------
template<class T, class D>
inline T& Boi::SharedPtr<T, D>::operator*() const
{
return *holder_ptr;
}
//-------------------------------------------------------------------------
template<class T, class D>
inline SharedPtr<T, D>& Boi::SharedPtr<T, D>::operator = ( const SharedPtr<T, D>& _ptr )
{
Swap(SharedPtr<T, D>(_ptr));
return *this;
}
//-------------------------------------------------------------------------
template<class T, class D>
inline Boi::SharedPtr<T, D>::~SharedPtr()
{
Release();
}
//-------------------------------------------------------------------------
template<class T, class D>
inline Boi::SharedPtr<T, D>::SharedPtr(T* _ptr)
: holder_ptr(_ptr)
{
if (holder_ptr)
{
ASSERT(ref_ptr = new long(1));
}
}
//-------------------------------------------------------------------------
template<class T, class D>
inline Boi::SharedPtr<T, D>::SharedPtr(const SharedPtr<T, D>& _ptr)
: ref_ptr(_ptr.ref_ptr), holder_ptr(_ptr.holder_ptr)
{
if (ref_ptr) ++(*ref_ptr);
}
//-------------------------------------------------------------------------
template<class T, class D>
inline Boi::SharedPtr<T, D>::SharedPtr()
: holder_ptr(NULL), ref_ptr(NULL)
{

}
//-------------------------------------------------------------------------
...全文
267 14 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
shilei_312 2014-09-17
  • 打赏
  • 举报
回复
引用 6 楼 Idle_ 的回复:
[quote=引用 5 楼 shilei_312 的回复:] [quote=引用 3 楼 Idle_ 的回复:] 楼主确定那玩意是shared_ptr? 感觉非常不对劲,考虑下面例子,似乎肯定误杀对象: 全局变量 SharedPtr<sometype> globalPtr; // 内部ref == 1, holder -> 实际对象 int somefunction() { SharedPtr<sometype> localPtr; // 内部ref == null,holder = null localPtr = globalPtr; // localPtr内部ref == 1, holder ->实际对象,GlobalPtr 内部则全部被置为null .... } // 退出时销毁localPtr因为ref==1所以同时销毁了holder指向的对象,GlobalPtr却莫名其妙指向null
感觉应该没有这个问题吧,赋值的时候构造了临时对象调用构造函数,只是递增引用计数,并没有改变GlobalPtr的内嵌指针啊,然后再和临时对象swap数据,刚才测试了一下,没有你说的问题,是不是只在某种情况下有这个问题呀?[/quote] 哪里需要构造临时对象的? 我例子里是直接赋值SharedPtr变量给SharedPtr变量啊,不就是直接调用了operator=吗?不就是直接swap两个SharedPtr内部变量吗? [/quote] operator = 是重载了的。 Swap(SharedPtr<T, D>(_ptr));
阿呆_ 2014-09-17
  • 打赏
  • 举报
回复
引用 5 楼 shilei_312 的回复:
[quote=引用 3 楼 Idle_ 的回复:] 楼主确定那玩意是shared_ptr? 感觉非常不对劲,考虑下面例子,似乎肯定误杀对象: 全局变量 SharedPtr<sometype> globalPtr; // 内部ref == 1, holder -> 实际对象 int somefunction() { SharedPtr<sometype> localPtr; // 内部ref == null,holder = null localPtr = globalPtr; // localPtr内部ref == 1, holder ->实际对象,GlobalPtr 内部则全部被置为null .... } // 退出时销毁localPtr因为ref==1所以同时销毁了holder指向的对象,GlobalPtr却莫名其妙指向null
感觉应该没有这个问题吧,赋值的时候构造了临时对象调用构造函数,只是递增引用计数,并没有改变GlobalPtr的内嵌指针啊,然后再和临时对象swap数据,刚才测试了一下,没有你说的问题,是不是只在某种情况下有这个问题呀?[/quote] 哪里需要构造临时对象的? 我例子里是直接赋值SharedPtr变量给SharedPtr变量啊,不就是直接调用了operator=吗?不就是直接swap两个SharedPtr内部变量吗?
shilei_312 2014-09-17
  • 打赏
  • 举报
回复
引用 3 楼 Idle_ 的回复:
楼主确定那玩意是shared_ptr? 感觉非常不对劲,考虑下面例子,似乎肯定误杀对象: 全局变量 SharedPtr<sometype> globalPtr; // 内部ref == 1, holder -> 实际对象 int somefunction() { SharedPtr<sometype> localPtr; // 内部ref == null,holder = null localPtr = globalPtr; // localPtr内部ref == 1, holder ->实际对象,GlobalPtr 内部则全部被置为null .... } // 退出时销毁localPtr因为ref==1所以同时销毁了holder指向的对象,GlobalPtr却莫名其妙指向null
感觉应该没有这个问题吧,赋值的时候构造了临时对象调用构造函数,只是递增引用计数,并没有改变GlobalPtr的内嵌指针啊,然后再和临时对象swap数据,刚才测试了一下,没有你说的问题,是不是只在某种情况下有这个问题呀?
jmppok 2014-09-17
  • 打赏
  • 举报
回复
这类问题就不要自己写了,用现成开源的就可以了. 自己写有以下缺点: 1.费时间,费精力; 2.不稳定,效率低;
阿呆_ 2014-09-17
  • 打赏
  • 举报
回复
楼主确定那玩意是shared_ptr? 感觉非常不对劲,考虑下面例子,似乎肯定误杀对象: 全局变量 SharedPtr<sometype> globalPtr; // 内部ref == 1, holder -> 实际对象 int somefunction() { SharedPtr<sometype> localPtr; // 内部ref == null,holder = null localPtr = globalPtr; // localPtr内部ref == 1, holder ->实际对象,GlobalPtr 内部则全部被置为null .... } // 退出时销毁localPtr因为ref==1所以同时销毁了holder指向的对象,GlobalPtr却莫名其妙指向null
jwj070524 2014-09-17
  • 打赏
  • 举报
回复
boost::shared_ptr里面是有锁的哦
  • 打赏
  • 举报
回复
引用 13 楼 Idle_ 的回复:
[quote=引用 12 楼 my3439955 的回复:] [quote=引用 11 楼 Idle_ 的回复:] [quote=引用 10 楼 my3439955 的回复:] shared_ptr中至少要有两个数据成员,一个是原始指针,一个是引用计数,这两个无法通过原子操作来改变,因此,无锁且线程安全的shared_ptr是不可能存在的。
这个可不一定,完全可以将引用计数变量即做锁又做普通指针。修改holder_ptr前同样先修改ref_ptr即可,只要将ref_ptr的值设置成一个即非0又非指针的数值(比如【0..65535】之间)即可分辨当前是否被锁,甚至还可以根据具体值分辨出被锁是在进行什么操作。 [/quote] 你开发出来无锁且线程安全的shared_ptr,c++11的shared_ptr可以歇着了[/quote] 很奇怪的逻辑,人家是自定义的SharedPtr, 和c++11的shared_ptr有什么关系? 凭什么不能做成线程安全的? 就算将std::shared_ptr改成线程安全的又有什么不可以的? 只要适合自己的应用需求就行了(比如需求中不需要考虑多线程同步造成的性能损失的话,完全可以做到不使用任何需要内核同步对象支持的线程同步--最多就是浪费点cpu执行效率不怎么样而已)[/quote] 当然可以做成线程安全的,现在说的是无锁且线程安全的
shilei_312 2014-09-17
  • 打赏
  • 举报
回复
自己顶一下!
阿呆_ 2014-09-17
  • 打赏
  • 举报
回复
引用 12 楼 my3439955 的回复:
[quote=引用 11 楼 Idle_ 的回复:] [quote=引用 10 楼 my3439955 的回复:] shared_ptr中至少要有两个数据成员,一个是原始指针,一个是引用计数,这两个无法通过原子操作来改变,因此,无锁且线程安全的shared_ptr是不可能存在的。
这个可不一定,完全可以将引用计数变量即做锁又做普通指针。修改holder_ptr前同样先修改ref_ptr即可,只要将ref_ptr的值设置成一个即非0又非指针的数值(比如【0..65535】之间)即可分辨当前是否被锁,甚至还可以根据具体值分辨出被锁是在进行什么操作。 [/quote] 你开发出来无锁且线程安全的shared_ptr,c++11的shared_ptr可以歇着了[/quote] 很奇怪的逻辑,人家是自定义的SharedPtr, 和c++11的shared_ptr有什么关系? 凭什么不能做成线程安全的? 就算将std::shared_ptr改成线程安全的又有什么不可以的? 只要适合自己的应用需求就行了(比如需求中不需要考虑多线程同步造成的性能损失的话,完全可以做到不使用任何需要内核同步对象支持的线程同步--最多就是浪费点cpu执行效率不怎么样而已)
  • 打赏
  • 举报
回复
引用 11 楼 Idle_ 的回复:
[quote=引用 10 楼 my3439955 的回复:] shared_ptr中至少要有两个数据成员,一个是原始指针,一个是引用计数,这两个无法通过原子操作来改变,因此,无锁且线程安全的shared_ptr是不可能存在的。
这个可不一定,完全可以将引用计数变量即做锁又做普通指针。修改holder_ptr前同样先修改ref_ptr即可,只要将ref_ptr的值设置成一个即非0又非指针的数值(比如【0..65535】之间)即可分辨当前是否被锁,甚至还可以根据具体值分辨出被锁是在进行什么操作。 [/quote] 你开发出来无锁且线程安全的shared_ptr,c++11的shared_ptr可以歇着了
阿呆_ 2014-09-17
  • 打赏
  • 举报
回复
引用 10 楼 my3439955 的回复:
shared_ptr中至少要有两个数据成员,一个是原始指针,一个是引用计数,这两个无法通过原子操作来改变,因此,无锁且线程安全的shared_ptr是不可能存在的。
这个可不一定,完全可以将引用计数变量即做锁又做普通指针。修改holder_ptr前同样先修改ref_ptr即可,只要将ref_ptr的值设置成一个即非0又非指针的数值(比如【0..65535】之间)即可分辨当前是否被锁,甚至还可以根据具体值分辨出被锁是在进行什么操作。
  • 打赏
  • 举报
回复
shared_ptr中至少要有两个数据成员,一个是原始指针,一个是引用计数,这两个无法通过原子操作来改变,因此,无锁且线程安全的shared_ptr是不可能存在的。
mujiok2003 2014-09-17
  • 打赏
  • 举报
回复
long* ref_ptr;
-->
std::atomic<long>* ref_ptr;
阿呆_ 2014-09-17
  • 打赏
  • 举报
回复
SharedPtr内需要同步的其实就是ref_ptr, 在所有使用ref_ptr的地方同步即可,一个简单的同步方法(不用锁)是访问ref_ptr前将其值用InterlockedCompareExchangePtr()改为特定值(比如swap前将其改成(long*)1, 删除前改成(long*)2)并判断返回值如果返回的是特定值,则表明有其它线程正在访问这个ref_ptr,那么用循环InterlockedCompareExchangePtr()+sleep()等待其它线程处理完成(特例,如果其它线程正在释放那么直接用null代替当前ref_ptr而不用等到对方完成),然后用返回的指针副本进行相应操作,等操作完成后用InterlockedExchange()将ref_ptr改回原来的指针。

5,530

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 模式及实现
社区管理员
  • 模式及实现社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧