多线程的析构
析构和多线程
鉴于C++没有(原生)垃圾回收机制,因此析构的race condition需要程序员来考虑
析构函数不需要锁来保证线程安全
析构函数不能用锁来保护,原因有:
1)基类与派生类的析构函数是割裂的,因此必然无法保证线程安全
2)安全的析构原则上只有其他线程都不用它时才是安全的,即成为“垃圾”时
这个结论较为显而易见
析构函数的race condition
析构函数有几个竞态条件:
1)析构的时候,是否有其他线程正在调用其成员函数
2)调用成员函数期间,其他线程是否正在析构其对象
3)在调用成员函数前,如何知道其是否存活
4)其他race condition
正如前面所说,如果有类似GC的机制就会好办很多
因此我们可以采取std::shared_ptr
来解决1),2),而与std::weak_ptr
组合成的弱回调(weak callback)可以解决3)
1)如果存在其他线程正在调用其成员函数,那么它的引用计数至少为1,不可能在析构
2)与1)同理,在调用成员函数期间,其他线程不可能正在析构其对象
3)通过std::weak_ptr
的lock()
原子提升为std::shared_ptr
,可以探明其是否存活
但请注意,在个别情况应用expired()
来代替lock()
,因为它引来了std::shared_ptr
的拷贝
设想如果对象A与B存在相互引用,在A的析构中我想探明B是否有它的引用,如果用lock()
,尽管可以保证其引用计数至少为2,但是如果突然另外一个线程将其析构,引用计数减1,待离开block scope时有得再次析构,这是很可能会陷入单线程重复加锁而陷入死锁
weak callback
1 | // 伪代码 |
weak callback 的语义为:若对象存活, 则调用其成员函数
可以进一步用模板抽象为function object
example
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Conzxy's blog!
评论