第一章:跨线程对象的生命期管理

本文探讨了在多线程环境中管理对象生命期的重要性,强调避免在构造函数中泄漏this指针,不在构造时注册回调,以及在析构函数中避免使用互斥量。建议采用二段式构造、智能指针如shared_ptr和weak_ptr搭配使用,以及对象池来解决线程安全问题。特别提到了Observer模式下避免对已销毁观察者的通知,以及对象池的实现细节。
摘要由CSDN通过智能技术生成


主旨

用流水线,生产者消费者,任务队列等机制尽量减少跨线程对象的使用。如果一定要用跨线程的对象,那么要注意安全地构造、使用和析构跨线程的对象。对于跨线程对象的使用可以通过mutex保护临界区实现线程安全,对象的生与死不能由对象自身拥有的mutex来保护,本章的重点在于跨线程对象的安全构造和析构问题。

一些基础知识

  • 可重入/不可重入函数:在函数调用还没有返回之前,该函数又被调用(比如被中断处理函数调用),处理完中断继续回来执行,函数执行所依赖的环境有没有发生改变。不可重入通常是因为引用了全局变量。

  • mutable:修饰非静态数据成员,在const成员函数中可以被改变

  • 线程安全的定义:多个线程同时访问,其表现出正确的行为;无论操作系统如何调度这些线程,无论这些线程的执行顺序如何交织,调用端代码无须额外的同步或者其他协调操作。STL大多数class都不是线程安全的

  • 空悬指针:指向已经销毁的对象或已经回收的地址;野指针:未经初始化的指针

  • scoped_ptr是boost库中的叫法,在C++11中叫unique_ptr

  • 对象的关系:

    1)composition组合/复合:x是owner的直接数据成员、scoped_ptr成员或者owner持有的容器的元素,x的生命周期由其owner控制。

    2)association关联:a调用b的成员函数,a持有b的指针或者引用,b的生命周期不受a控制。

    3)aggregation聚合:从形式上与association一样,但是a和b有逻辑上的整体与部分的关系,但是b可以脱离a独立存在,如车和引擎。

  • fucntion对象和bind

  • enable_shared_from_this: 要使用shared_from_this(), 该对象必须是堆对象,不能在构造函数中使用

构造函数的线程安全

准则:不要在构造函数中泄漏this指针,因为在构造函数中,对象还没有构造完全,这时如果别的线程对这个对象进行访问,访问到的是一个不完整的对象

  • 不要在构造函数中注册回调函数
  • 不要将this指针传给别的线程的对象
  • 即使在构造函数的最后一行也不要泄漏this指针,因为这可能是个基类,后续还要执行子类的构造

解决方法:二段式构造,即构造函数+initialize(),把要传递this指针的操作放到构造函数外面

析构函数的线程安全

不能依靠作为数据成员的mutex保护析构函数

  • 析构函数本来就不应该不需要用互斥量去保护,因为只有当别的线程访问不到这个对象时,析构才是安全的。
  • 用来保护析构函数的mutex必须是有效的,但是析构函数会把作为成员变量的mutex销毁掉
// 线程不安全的析构函数例子
Foo:~Foo(){
   
    MutexLockGuard lock(mutex_);
    ...
    }
void Foo::update(){
   
    MutexLockGuard lock(mutex_);
    ...
    }
    
// 线程A
delete x;
x = nullptr; // 没用
// 线程B
if(x){
   
x->update();
}

竞争条件:把对象的指针暴露给其他函数或者对象之后,如果对象销毁了,并不能通过指针判断出对象是否已经被销毁,这时候通过这个空悬指针访问,就会存在问题。这样的例子有:对于关联和聚合关系,如果b是动态创建的且在程序结束前有可能被释放,那么可能产生竞争条件;注册了任何非静态成员函数的回调,例如Oberver模式。

解决方法:

  • 对象池:不存在对象的销毁,但也有很多问题。
  • 智能指针:shared_ptr与weak_ptr搭配使用,要注意shared_ptr可能会延长对象的生存期以及循环引用问题。下面两个例子都用到了弱回调,弱回调是指如果对象还活着,就调用它的成员函数,否则忽略之,可以通过尝试将weak_ptr提升为shared_ptr,如果提升成功则表示对象还活着。

Observer模式

问题描述:被观察者保存观察者列表,当事件发生时,通知观察者列表里的每个观察者。这里存在的问题时,如果某个观察者已经析构了,被观察者如果仍然对通知这个观察者,就会出现coredump。本质上是,观察者将this指针传递给了被观察者,如何保障观察者的安全析构。

//Observer.h
class Observer {
   
public
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值