线程安全的对象生命期管理
-
编写线程安全的类不是难事,用同步原语保护内部状态即可。但是对象的生与死不能由对象自身拥有的mutex保护。
- race condition:在即将析构一个对象时,从何而知此刻是否有别的线程正在执行该对象的成员函数?如何保证在执行成员函数期间,对象不会在另一个线程被析构?在调用某个对象的成员函数之前如何得知这个对象还活着?它的析构函数会不会碰巧执行到一半?
- 对象构造要做到线程安全,唯一的要求就是在构造期间不要泄漏this指针。
- 作为class数据乘员的Mutex只能用于同步本class的其他数据成员读写,它不能安全的保护析构。因为Mutex的生命周期最多与对象一样长,而析构函动作可说是发生在对象身故之后(或者身故之时)。涉及到析构函数的多线程 会发生race condition。另外同时读写一个class的两个对象,有潜在的死锁可能。
- 观察者模式中 observable 和 observer的双向耦合时,怎么确定对方是否还存在。把Observer* 替换为weak_ptr<Observer>
- 神器shared_ptr/weak_ptr。shared_ptr是强引用,只要有一个指向x对象的shared_ptr存在,该对象就不会析构。当指向x的最后一个shared_ptr析构或者reset()的时候,x保证被销毁。weak_ptr不控制对象的生命期,但是它知道对象是否还活着。如果对象还活着,那么它可以提升为有效的shared_ptr(提升行为是线程安全的)。shared_ptr/weak_ptr在主流平台上是原子操作,没有用锁,性能不俗。shared_ptr的引用计数本身是线程安全的,它所管理的对象不是线程安全的,要在多个线程访问同一个shared_ptr,正确的做法是用mutex保护。
-
智能指针的优势:C++利用智能指针达到的效果是:一旦对象不再被引用,系统刻不容缓,立刻回收内存。
- 指向对象的原始指针是坏的,尤其是暴露给别的线程时。
- 统一使用shared_ptr/weak_ptr来管理对象的生命期,在多线程中尤其重要。