[关闭]
@zhuanxu 2018-05-24T04:14:50.000000Z 字数 1827 阅读 319

对象生命周期管理

c++


先定义什么叫线程安全:就是能够在多线程环境下使用,不需要通过额外的同步代码。

对象构造的线程安全

要保证对象的构造线程安全,我们需要做到在构造期间不将this指针泄露出去,因为在多线程环境下,有可能其他线程会使用到未构造完成的this指针。

即使我们在构造函数的最后一行,也不应该将this指针传递给其他线程,因为c++中基类早于派生类进行构造,此时有可能还要进行派生类的构造。

析构函数遇到多线程

问题:如何保证一个对象正在使用时不会被其他线程析构。

我们知道解决竞态的方法就是将所有操作排队,其中一种方法就是加锁,但是在多线程中,锁有可能会在析构函数中被释放,来看例子:

客户端代码:

在实际执行中,可能在Foo析构函数得到mutex锁之前,线程B已经在执行update了,并且阻塞在锁上,此时析构函数执行完后,锁就不存在了。程序行为未知。。。

从上面的例子我们看到了作为成员变量的mutex是无法保护析构函数的。

上面的例子中,如果我们有一种好的方法能够判断一个指针是否可用,我们就能该对象的状态了。

在面向对象中,对象的关系主要有3种:

其中组合两者的生命周期一致,不存在什么问题;关联是一种比较弱的关系,形式就是在函数中调用了另外一个对象的方法,此时我们就无法知道该对象是否还存活;聚合关系也是,因为不拥有成员对象的生命周期,所以也无法判断是否存活。

所以上面这种问题要想解决,我们还是得从对象指针入手,我们需要智能指针

我们先来回答一个问题:什么时候对象可以释放?
没有人使用的时候就可以释放了,于是我们就可以使用带引用计数的指针来解决是否有人使用的问题。

c++11中带来了解决方案 shared_ptr 和 weak_ptr ,其中 shared_ptr 在原始指针的基础上增加了一个引用计数,只要有程序中有引用,对象就不析构;weak_ptr 是弱引用,并不增加 shared_ptr 的引用计数。

另外需要特别注意的 shared_ptr 和 weak_ptr 都是值语义,意味着是以下几种情况

  1. 栈对象
  2. 对象成员
  3. 容器里元素

对于 shared_ptr ,我们使用拷贝构造和拷贝赋值的时候增加引用计数,而使用移动赋值和移动构造的时候转出控制权。

在 shared_ptr 的文档中提到多线程环境下:

If multiple threads of execution access the same shared_ptr without synchronization and any of those accesses uses a non-const member function of shared_ptr then a data race will occur; the shared_ptr overloads of atomic functions can be used to prevent the data race

如果多线程环境下使用shared_ptr,并且同时会去使用其管理对象的非const方法,那就需要额外的同步代码。

对象生命周期延长额

我们现在有了 share_ptr,通过它我们就能够很好个管理对象指针了,下面是一个使用 share_ptr 的例子:

get的逻辑是从map中找key,如果不存在就创建后返回,上面代码的一个问题是,由于使用shared_ptr管理,由于容器的存在,stock对象一直不会被释放,于是我们就有了下面的 weak_ptr 版本。

容器中保存weak_ptr,返回到外部的 shared_ptr 能够释放掉内存,但是容器中的weak_ptr却一直存在,所以我们有了第3个版本:


在 创建shared_ptr的时候传入析构函数,让其删除weak_ptr和stock对象。

但是上面版本的问题是:由于我们将stockFactory的指针传递给了Functor对象, 我们不能保证 share_ptr 对象的生命周期比 stockFactory 长,如果 stockFactory 先于 share_ptr 析构,会有问题,所以我们就有第4个版本,我们给 Functor 传递 shared_ptr 指针:

上面版本还有一个小问题: stockFactory 的生命周期被 share_ptr 延长了,于是我们就有了最后的版本,通过 weak_ptr 来传出 stockFactory 指针:

我们可以看到c++中通过 shared_ptr 和 weak_ptr 能够很好的解决内存管理问题。

以上内容来自 Linux多线程服务端编程第一章。

你的鼓励是我继续写下去的动力,期待我们共同进步。
这个时代,每个人都是超级个体!关注我,一起成长!

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注