C++ boost库中的sp_counted_base实现解析
2014-10-12 16:36
169 查看
boost库中对sp_counted_base实现根据不同的体系配备了不同的实现体,这里主要分析x86体系下的gcc实现版本。
在正式介绍该函数之前,需要介绍三个函数的实现。
inline int atomic_exchange_and_add( int * pw, int dv ),这个函数的作用:
1. 返回pw存放的数值
2. 修改*pw = *pw + dv
只不过这两个操作都是原子操作,通过在锁操作数地址的情况下,xadd指令完成交换和加法操作。
inline void atomic_increment( int * pw ),该函数作用:
原子对pw里面存放的数值递增,也是在锁操作数地址的情况下,通过incl指令完成
inline int atomic_conditional_increment( int * pw ),该函数作用:
if(*pw) ++*pw
并返回修改前pw存放的数值,这里采用的是cmpxchgl指令,具体代码如下:
int rv, tmp;
__asm__
(
"movl %0, %%eax\n\t"
"0:\n\t"
"test %%eax, %%eax\n\t"
"je 1f\n\t"
"movl %%eax, %2\n\t"
"incl %2\n\t"
"lock\n\t"
"cmpxchgl %2, %0\n\t"
"jne 0b\n\t"
"1:":
"=m"( *pw ), "=&a"( rv ), "=&r"( tmp ): // outputs (%0, %1, %2)
"m"( *pw ): // input (%3)
"cc" // clobbers
);1. 将*pw存放的数值放入到eax寄存器中
2. 开始判断,如果eax寄存器中保存的数值=0,那么跳到7
3. 将eax里面的数值存放一份到tmp中
4. 对tmp里面的数值进行+1操作
5. 如果*pw里面的数值等于eax里面的数值(如果我们在将*pw的数值取出来之后,后续操作并没有改变*pw),那么将tmp数值写入到pw位置,并设置ZF=1,否则,将*pw里面的数值放入到eax中,也就是重新更新了eax里面的数值,让eax永远等于*pw里面存放的数值
6. 如果在我们准备修改*pw之前,*pw数值已经发生改变,说明这时候我们不能对*pw进行修改,否则会出现写后写的错误情况,此时就应该重新获取新的*pw,并在新的*pw上进行操作,并尝试在此对*pw进行修改,即跳转到2处。如果上步骤修改成功,那么就返回修改前的*pw数值
7. 返回*pw修改前的数值
sp_counted_base是包含在boost::detail命名空间下的一个类,大致原型如下:
首先从这个类的构造函数入口,其复制构造函数和赋值构造函数被声明为private,这样就避免了通过复制和赋值操作来产生一个新的对象。
那么新的对象如何产生呢?
只能通过定义来产生一个默认的对象,并且这个对象里面的两个成员变量都被赋值为默认值,也就是不能再构造这个对象的时候手动的指定成员变量的值。说到成员变量,sp_counted_base有两个私有的成员变量。
use_count_,主要用于shared_ptr智能指针用来管理计数的。在后续的shared_ptr章节会有介绍。
weak_count_,用于weak_ptr智能指针用来管理计数的,在后续的weak_ptr会介绍。
说完构造函数,析构函数就比较简单了,由于这个类没有管理动态资源,故析构函数是一个空函数,并且实现为虚函数,主要用于管理子类的时候能够正确的调用子类的析构函数,而非错误的调用父类的析构函数。
destroy函数,这个函数就是去销毁一个对象,当然这个对象可能是自身或者子类,也定义为虚函数,方便后续不同的子类来复写,从而实现多态。
use_count函数,这个函数申明为const类型,表明这个函数不会对对象中的变量进行修改,返回use_count_变量的数值,只不过再返回的时候进行了类型的转换,这里使用了const volatile两个来修饰,说明这个变量首先对于返回值来说是一个常量,同时volatile同时告诉编译器这个常量的读取不能够从缓存在寄存器中进行读取,而要从内存中去读取,以防止数据的不一致性。
add_ref_copy函数,调用atomic_increament函数对use_count_变量进行原子+1操作,这个函数主要供shared_ptr调用
add_ref_lock函数,调用atomic_conditional_increament函数对use_count_变量+1操作,主要用于weak_ptr到shared_ptr转换时候使用,因为一个weak_ptr对象,如果计数为0,那么就无法转换为一个shared_ptr对象,这里正是通过atomic_conditional_increament函数来正确的管理计数。
weak_add_ref函数,类型于add_ref_copy,只不过区别是对weak_count_变量+1操作
weak_release函数,进行两部操作,首先将weak_count_修改为weak_count_-1,然后判断weak_count以前的数值是否为1,如果为1说明目前这个调用weak_release函数的对象是最后一个拥有某项资源的对象,那么就调用destory来释放这个对象,当然根据destory函数是一个虚函数,会释放具体的子类。
release函数,这个函数是对use_count_变量进行类型与weak_release的操作,一点区别是不会直接调用destory函数,取而代之的是调用dispose和weak_release函数,其中dispose函数是一个纯虚函数,需要子类具体实现,目的是用于释放该对象所管理的具体资源,也就是给资源销毁一个时机。并通过weak_release来销毁该对象。
还有两个纯虚函数get_deleter和get_untyped_deleter,都需要子类去具体实现。
在正式介绍该函数之前,需要介绍三个函数的实现。
inline int atomic_exchange_and_add( int * pw, int dv ),这个函数的作用:
1. 返回pw存放的数值
2. 修改*pw = *pw + dv
只不过这两个操作都是原子操作,通过在锁操作数地址的情况下,xadd指令完成交换和加法操作。
inline void atomic_increment( int * pw ),该函数作用:
原子对pw里面存放的数值递增,也是在锁操作数地址的情况下,通过incl指令完成
inline int atomic_conditional_increment( int * pw ),该函数作用:
if(*pw) ++*pw
并返回修改前pw存放的数值,这里采用的是cmpxchgl指令,具体代码如下:
int rv, tmp;
__asm__
(
"movl %0, %%eax\n\t"
"0:\n\t"
"test %%eax, %%eax\n\t"
"je 1f\n\t"
"movl %%eax, %2\n\t"
"incl %2\n\t"
"lock\n\t"
"cmpxchgl %2, %0\n\t"
"jne 0b\n\t"
"1:":
"=m"( *pw ), "=&a"( rv ), "=&r"( tmp ): // outputs (%0, %1, %2)
"m"( *pw ): // input (%3)
"cc" // clobbers
);1. 将*pw存放的数值放入到eax寄存器中
2. 开始判断,如果eax寄存器中保存的数值=0,那么跳到7
3. 将eax里面的数值存放一份到tmp中
4. 对tmp里面的数值进行+1操作
5. 如果*pw里面的数值等于eax里面的数值(如果我们在将*pw的数值取出来之后,后续操作并没有改变*pw),那么将tmp数值写入到pw位置,并设置ZF=1,否则,将*pw里面的数值放入到eax中,也就是重新更新了eax里面的数值,让eax永远等于*pw里面存放的数值
6. 如果在我们准备修改*pw之前,*pw数值已经发生改变,说明这时候我们不能对*pw进行修改,否则会出现写后写的错误情况,此时就应该重新获取新的*pw,并在新的*pw上进行操作,并尝试在此对*pw进行修改,即跳转到2处。如果上步骤修改成功,那么就返回修改前的*pw数值
7. 返回*pw修改前的数值
sp_counted_base是包含在boost::detail命名空间下的一个类,大致原型如下:
<span style="font-size:18px;">class sp_counted_base { private: sp_counted_base( sp_counted_base const & ); sp_counted_base & operator= ( sp_counted_base const & ); int use_count_; // #shared int weak_count_; // #weak + (#shared != 0) public: sp_counted_base(): use_count_( 1 ), weak_count_( 1 ) { } virtual ~sp_counted_base() // nothrow { } virtual void dispose() = 0; // nothrow virtual void destroy() // nothrow { delete this; } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() { atomic_increment( &use_count_ ); } bool add_ref_lock() // true on success { return atomic_conditional_increment( &use_count_ ) != 0; } void release() // nothrow { if( atomic_exchange_and_add( &use_count_, -1 ) == 1 ) { dispose(); weak_release(); } } void weak_add_ref() // nothrow { atomic_increment( &weak_count_ ); } void weak_release() // nothrow { if( atomic_exchange_and_add( &weak_count_, -1 ) == 1 ) { destroy(); } } long use_count() const // nothrow { return static_cast<int const volatile &>( use_count_ ); } };</span>
首先从这个类的构造函数入口,其复制构造函数和赋值构造函数被声明为private,这样就避免了通过复制和赋值操作来产生一个新的对象。
那么新的对象如何产生呢?
只能通过定义来产生一个默认的对象,并且这个对象里面的两个成员变量都被赋值为默认值,也就是不能再构造这个对象的时候手动的指定成员变量的值。说到成员变量,sp_counted_base有两个私有的成员变量。
use_count_,主要用于shared_ptr智能指针用来管理计数的。在后续的shared_ptr章节会有介绍。
weak_count_,用于weak_ptr智能指针用来管理计数的,在后续的weak_ptr会介绍。
说完构造函数,析构函数就比较简单了,由于这个类没有管理动态资源,故析构函数是一个空函数,并且实现为虚函数,主要用于管理子类的时候能够正确的调用子类的析构函数,而非错误的调用父类的析构函数。
destroy函数,这个函数就是去销毁一个对象,当然这个对象可能是自身或者子类,也定义为虚函数,方便后续不同的子类来复写,从而实现多态。
use_count函数,这个函数申明为const类型,表明这个函数不会对对象中的变量进行修改,返回use_count_变量的数值,只不过再返回的时候进行了类型的转换,这里使用了const volatile两个来修饰,说明这个变量首先对于返回值来说是一个常量,同时volatile同时告诉编译器这个常量的读取不能够从缓存在寄存器中进行读取,而要从内存中去读取,以防止数据的不一致性。
add_ref_copy函数,调用atomic_increament函数对use_count_变量进行原子+1操作,这个函数主要供shared_ptr调用
add_ref_lock函数,调用atomic_conditional_increament函数对use_count_变量+1操作,主要用于weak_ptr到shared_ptr转换时候使用,因为一个weak_ptr对象,如果计数为0,那么就无法转换为一个shared_ptr对象,这里正是通过atomic_conditional_increament函数来正确的管理计数。
weak_add_ref函数,类型于add_ref_copy,只不过区别是对weak_count_变量+1操作
weak_release函数,进行两部操作,首先将weak_count_修改为weak_count_-1,然后判断weak_count以前的数值是否为1,如果为1说明目前这个调用weak_release函数的对象是最后一个拥有某项资源的对象,那么就调用destory来释放这个对象,当然根据destory函数是一个虚函数,会释放具体的子类。
release函数,这个函数是对use_count_变量进行类型与weak_release的操作,一点区别是不会直接调用destory函数,取而代之的是调用dispose和weak_release函数,其中dispose函数是一个纯虚函数,需要子类具体实现,目的是用于释放该对象所管理的具体资源,也就是给资源销毁一个时机。并通过weak_release来销毁该对象。
还有两个纯虚函数get_deleter和get_untyped_deleter,都需要子类去具体实现。
相关文章推荐
- C++boost库中sp_counted_impl_x实现解析
- 设计模式解析的C++实现
- SIP协议解析与实现(c和c++使用osip) 2
- 常见设计模式的解析和实现(C++)之六-Adapt模式
- 常见设计模式的解析和实现(C++)之一-Factory模式
- 常见设计模式的解析和实现(C++)之二-Abstract Factory模式
- 用Visual C++.NET实现XML解析
- SIP协议解析与实现(c和c++ 使用osip) 9
- 常见设计模式的解析和实现(C++)之八-Composite模式
- 常见设计模式的解析和实现(C++)之九-Decorator模式
- SIP协议解析与实现(c和c++使用osip) 7
- 常见设计模式的解析和实现(C++)之二十一-完结篇
- 常见设计模式的解析和实现(C++)之十六-Strategy模式
- 常见设计模式的解析和实现(C++)之十七-State模式
- 常见设计模式的解析和实现(C++)之七-Bridge模式
- SIP协议解析与实现(c和c++使用osip) 1
- 常见设计模式的解析和实现(C++)之十八-Iterator模式
- 常见设计模式的解析和实现(C++)之十四-Command模式
- 常见设计模式的解析和实现(C++)之四-Prototype模式
- SIP协议解析与实现(c和c++ 使用osip) 8