`
aspnetwinform
  • 浏览: 84548 次
  • 性别: Icon_minigender_2
  • 来自: 武汉
社区版块
存档分类
最新评论

从零开始学C++之boost库(一):详解 boost 库智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> 源码分析)

 
阅读更多

一、boost 智能指针


智能指针是利用RAII(Resource Acquisition Is Initialization:资源获取即初始化)来管理资源。关于RAII的讨论可以参考前面的


。在使用boost库之前应该先下载后放在某个路径,并在VS 包含目录中添加。下面是boost 库里面的智能指针:




(一)、scoped_ptr<T>

先来看例程:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br></nobr>
#include<boost/scoped_ptr.hpp>
#include<iostream>
usingnamespacestd;

classX
{
public:
X()
{
cout<<"X..."<<endl;
}
~X()
{
cout<<"~X..."<<endl;
}
};

intmain(void)
{
cout<<"Enteringmain..."<<endl;
{
boost::scoped_ptr<X>pp(newX);

//boost::scoped_ptr<X>p2(pp);//Error:所有权不能转移
}
cout<<"Exitingmain..."<<endl;

return0;
}



来稍微看一下scoped_ptr 的简单定义:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br></nobr>
namespaceboost
{

template<typenameT>classscoped_ptr:noncopyable
{
private:

T*px;

scoped_ptr(scoped_ptrconst&);
scoped_ptr&operator=(scoped_ptrconst&);

typedefscoped_ptr<T>this_type;

voidoperator==(scoped_ptrconst&)const;
voidoperator!=(scoped_ptrconst&)const;
public:
explicitscoped_ptr(T*p=0);
~scoped_ptr();

explicitscoped_ptr(std::auto_ptr<T>p):px(p.release());
voidreset(T*p=0);

T&operator*()const;
T*operator->()const;
T*get()const;

voidswap(scoped_ptr&b);
};

template<typenameT>
voidswap(scoped_ptr<T>&a,scoped_ptr<T>&b);
}

auto_ptr类似,内部也有一个T* px; 成员 ,智能指针对象pp 生存期到了,调用析构函数,在析构函数内会delete px; 如下面所说:


scoped_ptr mimics a built-in pointer except that it guarantees deletionof the object pointed to, either on destruction of the scoped_ptr or viaan


explicit reset(). scoped_ptr is a simple solution for simple needs;use shared_ptr or std::auto_ptr if your needs are more complex.


从上面的话可以得知当调用reset() 函数时也能够释放堆对象,如何实现的呢?

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br></nobr>
voidreset(T*p=0)//neverthrows
{
BOOST_ASSERT(p==0||p!=px);//catchself-reseterrors
this_type(p).swap(*this);
}
voidswap(scoped_ptr&b)//neverthrows
{
T*tmp=b.px;
b.px=px;
px=tmp;
}

typedef scoped_ptr<T> this_type; 当调用pp.reset(),reset 函数构造一个临时对象,它的成员px=0, 在swap 函数中调换 pp.px 与


(this_type)(p).px, 即现在pp.px = 0; //解绑


临时对象接管了裸指针(即所有权可以交换),reset 函数返回,栈上的临时对象析构,调用析构函数,进而delete px;


另外拷贝构造函数和operator= 都声明为私有,故所有权不能转移,且因为容器的push_back 函数需要调用拷贝构造函数,故也不能


将scoped_ptr 放进vector,这点与auto_ptr 相同(不能共享所有权)。此外,还可以使用 auto_ptr 对象 构造一个scoped_ptr 对象:


scoped_ptr( std::auto_ptr<T> p ): px( p.release() );


由于scoped_ptr是通过delete来删除所管理对象的,而数组对象必须通过deletep[]来删除,因此boost::scoped_ptr是不能管理数组对象的,如果


要管理数组对象需要使用boost::scoped_array类。


boost::scoped_ptr和std::auto_ptr的功能和操作都非常类似,如何在他们之间选取取决于是否需要转移所管理的对象的所有权(如是否需要作为


函数的返回值)。如果没有这个需要的话,大可以使用boost::scoped_ptr,让编译器来进行更严格的检查,来发现一些不正确的赋值操作。


(二)、shared_ptr<T>


An enhanced relative of scoped_ptr with reference counted copy semantics.The object pointed to is deleted when the last

shared_ptr pointing to it is destroyed or reset.


先来看例程:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br></nobr>
#include<boost/shared_ptr.hpp>
#include<iostream>
usingnamespacestd;

classX
{
public:
X()
{
cout<<"X..."<<endl;
}
~X()
{
cout<<"~X..."<<endl;
}
};

intmain(void)
{
cout<<"Enteringmain..."<<endl;
boost::shared_ptr<X>p1(newX);
cout<<p1.use_count()<<endl;
boost::shared_ptr<X>p2=p1;
//boost::shared_ptr<X>p3;
//p3=p1;

cout<<p2.use_count()<<endl;
p1.reset();
cout<<p2.use_count()<<endl;
p2.reset();
cout<<"Exitingmain..."<<endl;
return0;
}

图示上述程序的过程也就是:


再深入一点,看源码,shared_ptr 的实现 比 scoped_ptr 要复杂许多,涉及到多个类,下面就不贴完整源码,看下面的类图:


执行boost::shared_ptr<X>p1(newX); 这一行之后:

而执行 p1.use_count(); 先是pn.use_count(); 接着pi_ != 0? pi_->use_count(): 0; return use_count_; 即返回1.


接着执行boost::shared_ptr<X>p2=p1;


本想跟踪shared_ptr 的拷贝构造函数,在当行设置断点后F11直接跳过了,说明是shared_ptr类没有实现拷贝构造函数,使用的是编译器默认的拷


贝构造函数,那如何跟踪呢?如果你的C++基础比较好,可以想到拷贝构造函数跟构造函数一样,如果有对象成员是需要先构造对象成员的(这一点


也可以从调用堆栈上看出),故可以在shared_count 类的拷贝构造函数设置断点,然后就可以跟踪进去,如下的代码:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br></nobr>
// shared_count
shared_count(shared_countconst&r):pi_(r.pi_)//nothrow
{
if(pi_!=0)pi_->add_ref_copy();
}
// sp_counted_base
voidadd_ref_copy()
{
BOOST_INTERLOCKED_INCREMENT(&use_count_);
}

故p2.pn.pi_ 也指向 唯一的一个 sp_counted_impl_p 对象,且use_count_ 增1.


再者,shared_ptr 类的默认拷贝构造函数是浅拷贝,故现在p2.px 也指向 X.


由于p2 和 p1 共享一个sp_counted_impl_p 对象,所以此时无论打印p2.use_count(); 还是 p1.use_count(); 都是2。


接着执行p1.reset();


C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br></nobr>
// shared_ptr
voidreset()//neverthrowsin1.30+
{
this_type().swap(*this);
}
voidswap(shared_ptr<T>&other)//neverthrows
{
std::swap(px,other.px);
pn.swap(other.pn);
}

this_type() 构造一个临时对象,px = 0, pn.pi_ = 0; 然后swap交换p1 与 临时对象的成员,即现在p1.px = 0; p1.pn.p1_ = 0; 如上图。


reset 函数返回,临时对象需要析构,但跟踪时却发现直接返回了,原因跟上面的一样,因为shared_ptr 没有实现析构函数,调用的是默认的析构函


数,与上面拷贝函数同样的道理,可以在shared_count 类析构函数设置断点,因为pn 是对象成员,故析构函数也会被调用。如下代码:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br></nobr>
//shared_count
~shared_count()//nothrow
{
if(pi_!=0)pi_->release();
}

// sp_counted_base
voidrelease()//nothrow
{
if(BOOST_INTERLOCKED_DECREMENT(&use_count_)==0)
{
dispose();
weak_release();
}
}

现在use_count_ 减为1,但还不为0,故dispose(); 和weak_release(); 两个函数没有被调用。当然此时打印 p2.use_count() 就为1 了。


最后 p2.reset(); 跟p1.reset(); 同样的流程,只不过现在执行到release 时,use_count_ 减1 为0;需要继续执行dispose(); 和


weak_release(); 如下代码:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br></nobr>

//sp_counted_impl_p
virtualvoiddispose()//nothrow
{
boost::checked_delete(px_);
}
//sp_counted_base
voidweak_release()//nothrow
{
if(BOOST_INTERLOCKED_DECREMENT(&weak_count_)==0)
{
destroy();
}
}

virtualvoiddestroy()//nothrow
{
deletethis;
}

在check_delete 中会 delete px_; 也就是析构 X。接着因为weak_count_ 减1 为0, 故执行destroy(); 函数里面delete this; 即析构自身


(sp_counted_impl_p 对象是在堆上分配的)。


说到这里,我们也可以明白,即使最后没有调用p2.reset(); 当p2 栈上对象生存期到, 需要调用shared_ptr 类析构函数,进而调用shared_count 类析


构函数,所以执行的结果也是跟reset() 一样的,只不过少了临时对象this_type()的构造。


总结一下:

和前面介绍的boost::scoped_ptr相比,boost::shared_ptr可以共享对象的所有权,因此其使用范围基本上没有什么限制(还是有一些需要遵循的

使用规则,下文中介绍),自然也可以使用在stl的容器中。另外它还是线程安全的,这点在多线程程序中也非常重要。

boost::shared_ptr并不是绝对安全,下面几条规则能使我们更加安全的使用boost::shared_ptr:

  1. 避免对shared_ptr所管理的对象的直接内存管理操作,以免造成该对象的重释放

  2. shared_ptr并不能对循环引用的对象内存自动管理(这点是其它各种引用计数管理内存方式的通病)。

  3. 不要构造一个临时的shared_ptr作为函数的参数。

详见http://www.boost.org/doc/libs/1_52_0/libs/smart_ptr/shared_ptr.htm

如下列bad 函数内 的代码则可能导致内存泄漏:
C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br></nobr>
voidf(shared_ptr<int>,int);
intg();

voidok()
{
shared_ptr<int>p(newint(2));
f(p,g());
}

voidbad()
{
f(shared_ptr<int>(newint(2)),g());
}

如bad 函数内,假设先构造了堆对象,接着执行g(), 在g 函数内抛出了异常,那么由于裸指针还没有被智能指针接管,就会出现内存泄漏。


(三)、weak_ptr<T>

如上总结shared_ptr<T> 时说引用计数是一种便利的内存管理机制,但它有一个很大的缺点,那就是不能管理循环引用的对象。

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br></nobr>
#include<boost/shared_ptr.hpp>
#include<iostream>
usingnamespacestd;

classParent;
classChild;
typedefboost::shared_ptr<Parent>parent_ptr;
typedefboost::shared_ptr<Child>child_ptr;

classChild
{
public:
Child()
{
cout<<"Child..."<<endl;
}
~Child()
{
cout<<"~Child..."<<endl;
}
parent_ptrparent_;
};

classParent
{
public:
Parent()
{
cout<<"Parent..."<<endl;
}
~Parent()
{
cout<<"~Parent..."<<endl;
}
child_ptrchild_;
};

intmain(void)
{
parent_ptrparent(newParent);
child_ptrchild(newChild);
parent->child_=child;
child->parent_=parent;

return0;
}

如上述程序的例子,运行程序可以发现Child 和 Parent 构造函数各被调用一次,但析构函数都没有被调用。由于Parent和Child对象互相引用,


它们的引用计数最后都是1,不能自动释放,并且此时这两个对象再无法访问到。这就引起了内存泄漏

其中一种解决循环引用问题的办法是 手动打破循环引用,如在return 0; 之前加上一句parent->child_.reset(); 此时

当栈上智能指针对象child 析构,Child 对象引用计数为0,析构Chlid 对象,它的成员parent_ 被析构,则Parent 对象引用计数

减为1,故当栈上智能指针对象parent 析构时,Parent 对象引用计数为0,被析构。


但手动释放不仅麻烦而且容易出错,这里主要介绍一下弱引用智能指针 weak_ptr<T> 的用法,下面是简单的定义:
C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br></nobr>
namespaceboost
{

template<typenameT>classweak_ptr
{
public:
template<typenameY>
weak_ptr(constshared_ptr<Y>&r);

weak_ptr(constweak_ptr&r);

template<classY>
weak_ptr&operator=(weak_ptr<Y>&&r);

template<classY>
weak_ptr&operator=(shared_ptr<Y>const&r);


~weak_ptr();

boolexpired()const;
shared_ptr<T>lock()const;
};
}

上面出现了 && 的用法,在这里并不是逻辑与的意思,而是C++ 11中的新语法,如下解释:


&&is new in C++11, and it signifies that the function accepts anRValue-Reference-- that is, a reference to an argument that is about

to be destroyed. //也就是说函数接受左值引用,也就是引用着的变量可以被修改


两个常用的功能函数:expired()用于检测所管理的对象是否已经释放;lock()用于获取所管理的对象的强引用智能指针。


强引用与弱引用

强引用,只要有一个引用存在,对象就不能释放

弱引用,并不增加对象的引用计数(实际上是不增加use_count_, 会增加weak_count_);但它能知道对象是否存在

通过weak_ptr访问对象的成员的时候,要提升为shared_ptr

如果存在,提升为shared_ptr(强引用)成功
如果不存在,提升失败

对于上述的例子,只需要将Parent 类里面的成员定义改为如下,即可解决循环引用问题:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br></nobr>
classParent
{
public:
boost::weak_ptr<parent>child_;
};

因为此例子涉及到循环引用,而且是类成员引用着另一个类,涉及到两种智能指针,跟踪起来难度很大,我也没什么心情像分析

shared_ptr 一样画多个图来解释流程,这个例子需要解释的代码远远比shared_ptr 多,这里只是解释怎样使用,有兴趣的朋友自

己去分析一下。


下面再举个例子说明lock() 和 expired() 函数的用法:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br></nobr>
#include<boost/shared_ptr.hpp>
#include<boost/weak_ptr.hpp>
#include<boost/scoped_array.hpp>
#include<boost/scoped_ptr.hpp>
#include<iostream>
usingnamespacestd;

classX
{
public:
X()
{
cout<<"X..."<<endl;
}
~X()
{
cout<<"~X..."<<endl;
}

voidFun()
{
cout<<"Fun..."<<endl;
}
};
intmain(void)
{
boost::weak_ptr<X>p;
boost::shared_ptr<X>p3;
{
boost::shared_ptr<X>p2(newX);
cout<<p2.use_count()<<endl;
p=p2;
cout<<p2.use_count()<<endl;

/*boost::shared_ptr<X>*/
p3=p.lock();
cout<<p3.use_count()<<endl;
if(!p3)
cout<<"objectisdestroyed"<<endl;
else
p3->Fun();
}
/*boost::shared_ptr<X>p4=p.lock();
if(!p4)
cout<<"objectisdestroyed"<<endl;
else
p4->Fun();*/


if(p.expired())
cout<<"objectisdestroyed"<<endl;
else
cout<<"objectisalived"<<endl;

return0;
}



从输出可以看出,当p = p2; 时并未增加use_count_,所以p2.use_count() 还是返回1,而从p 提升为 p3,增加了

use_count_, p3.use_count() 返回2;出了大括号,p2 被析构,use_count_ 减为1,程序末尾结束,p3 被析构,

use_count_ 减为0,X 就被析构了。


参考 :

C++ primer 第四版
Effective C++ 3rd
C++编程规范

http://www.cnblogs.com/TianFang/


分享到:
评论

相关推荐

    浅析Boost智能指针:scoped_ptr shared_ptr weak_ptr

    虽然通过弱引用指针可以有效的解除循环引用,但这种方式必须在程序员能预见会出现循环引用的情况下才能使用,也可以是说这个仅仅是一种编译期的解决方案,如果程序在运行过程中出现了循环引用,还是会造成内存泄漏的

    C++智能指针详解.pdf

    C++智能指针详解 智能指针详解 智能指针内容很多,重点是基本⽤法。 #include &lt;boost/shared_ptr.hpp&gt; class CBase: public boost::enable_shared_from_this&lt;CBase&gt; { public: virtual void f(){}//必须有个虚函数...

    C++智能指针用法详解

    一、简介  由于 C++ 语言没有自动...包括:std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array、boost::weak_ptr、boost:: intrusive_ptr。你可能会想,如此多的智能指

    C++智能指针实例详解

    本文通过实例详细阐述了C++关于智能指针的概念及用法,有助于读者加深对智能指针的理解。...包括:std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array、boost::

    C++11 下使用 Boost.Serialization 库实现智能指针的序列化

    C++11 下使用 Boost.Serialization 库实现智能指针的序列化

    c++ boost 开发参考手册

    最近开发中用到大量BOOST库的东西,现在把我开发中总结的boost使用方法分享一下,里面包括智能指针、boost定时器、boostthread和io_service等的用法和说明,还有一本Beyond the C++ Standard Library: An ...

    一键删除全部Selenium缓存(scoped-dir缓存文件)

    ●拿到脚本后,可以利用pyinstaller库进行封装生成一个程序。方便点击一键删除缓存。 ●代码:pyinstaller -F 文件名.py,生成程序后,在py文件目录下生成的dist文件夹里生成程序文件。直接将其拷贝到自己能操作的...

    THE BOOST C++ LIBRARIES

    THE BOOST C++ LIBRARIES是一份自己编译的chm格式文档,描述了如何使用boost类库,目录如下: Front page Chapter 1: Introduction 1.1 C++ and Boost 1.2 Development Process 1.3 Installation 1.4 Overview ...

    lab03_shared_ptr

    Например,класс scoped_refptr (аналог std::shared_ptr )используетсявChrome 。 Чтобылучшеусвоитьипонятьпринципработыэтого...

    程序员需要经常刷题吗-scoped_attr_accessor:将私有和受保护的attr_accessor方法添加到您的类-或所有ruby

    'scoped_attr_accessor' 然后执行: $ bundle 或者自己安装: $ gem install scoped_attr_accessor 用法 您可以通过直接在您的类中扩展ScopedAttrAccessor来将范围访问器添加到单个类(及其子类): require 'scoped...

    C++标准库(第二版)英文版.pdf

    C++标准库(第二版)英文版.pdf 非扫描版+源代码 Prefaceto the SecondEdition xxiii Acknowledgments for the SecondEdition xxiv Prefaceto the FirstEdition xxv Acknowledgments for the FirstEdition xxvi 1 ...

    scoped_from:提供Ruby On Rails的范围和控制器参数之间的简单映射

    范围从 提供作用域和控制器参数之间的简单映射。 安装 只需将其添加到您的Gemfile : gem 'scoped_from' 然后,只需运行bundle install 。 例子 首先,有一些范围的模型: class Post &lt; ActiveRecord&gt; 0' ) ...

    【JavaScript源代码】如何在vue-cli中使用css-loader实现css module.docx

    如何在vue-cli中使用css-loader实现css module ... 例子: &lt;div&gt; &lt;div class="demo"&gt; &lt;div class="child"&gt;&lt;/ div&gt; &lt;/div&gt; &lt;/div&gt; &lt;script&gt; // some code &lt;script/&gt; &lt;style lang="less" scoped&gt; .demo { 

    doctest.pdf

    &lt;template&gt; &lt;div&gt; &lt;router-view&gt;&lt;/router-view&gt; &lt;/div&gt; &lt;/template&gt; &lt;script&gt; export default { name: "app" }; &lt;/script&gt; &lt;style lang="scss" scoped&gt; &lt;/style&gt;

    cmd.reg.txt

    &lt;template&gt; &lt;div class="tableComponent"&gt; &lt;div class="tableElement"&gt; &lt;el-table :data="tableData" border :height="tableHeight" :header-cell-style="getHeadCellClass" style="width: 100%"&gt; &lt;template...

    Google C++ Style Guide(Google C++编程规范)高清PDF

    The format of the symbol name should be &lt;PROJECT&gt;_&lt;PATH&gt;_&lt;FILE&gt;_H_. To guarantee uniqueness, they should be based on the full path in a project's source tree. For example, the file foo/src/bar/baz.h...

    【JavaScript源代码】JS实现时间轴自动播放.docx

    JS实现时间轴自动播放 ...DOCTYPE html&gt; &lt;html&gt; &lt;head&gt; &lt;meta charset="utf-8" /&gt; &lt;title&gt;&lt;/title&gt; &lt;link rel="stylesheet" type="text/css" href="fonts/iconfont.css" /&gt; &lt;style scoped&gt; ul

    深入浅析Vue中的slots/scoped slots

    下面结合一个例子,简单说明slots的工作原理 dx-li子组件的template如下: &lt;li class=dx-li&gt; &lt;slot&gt; 你好! &lt;/slot&gt; &lt;/li&gt; dx-ul父组件的template如下: &lt;ul&gt; &lt;dx&gt; hello juejin! &lt;/dx&gt; &lt;/ul&gt; 结合上述例子...

    基于Boost的数据处理器及线程安全类和信号量

    4. 封装了boost的mutex的scoped_lock,能跨平台使用。相对于CWnLock,其优势在于发生异常时能自动解锁,避免线程死锁。 5. // 一个可用于线程间传递数据的类。此类的优势在于: // 1. 跨平台 // 2. 将线程通信间...

Global site tag (gtag.js) - Google Analytics