std::shared_ptr
是 ,用于管理动态分配的对象。它提供了引用计数的机制,允许多个 shared_ptr
共享同一个对象,并在不再需要时自动释放对象。
底层实现:
std::shared_ptr
的底层实现通常使用两个部分:一个控制块(control block)和一个指向实际对象的指针。控制块通常包含引用计数、指向对象的指针以及其他辅助信息。当创建一个 shared_ptr
对象时,控制块会被动态分配,并将引用计数初始化为 1。每当有一个新的 shared_ptr
对象指向相同的对象时,引用计数就会增加。当引用计数减少到零时,控制块会负责释放对象的内存。
线程安全性:
std::shared_ptr
的默认实现在引用计数的增加和减少操作上是线程安全的。这意味着多个线程可以并发地操作同一个 shared_ptr
对象而不需要外部同步。引用计数的增加和减少操作使用原子操作来确保线程安全性。然而,对于指向同一个对象的不同 shared_ptr
的复制构造函数和赋值操作符的并发调用,需要额外的同步机制来保证线程安全。
如果需要在多线程环境中使用 std::shared_ptr
,可以采取以下几种方法来确保线程安全性:
-
使用互斥锁(
std::mutex
):在对shared_ptr
进行复制构造或赋值操作时,使用互斥锁来保护共享资源的访问,以避免竞态条件。 -
使用原子操作(
std::atomic
):C++11 引入了原子操作,可以用于对引用计数的增加和减少操作进行原子操作,从而避免竞态条件。 -
使用线程局部存储(Thread-Local Storage, TLS):每个线程维护自己的
shared_ptr
实例,以避免多个线程之间的竞争。这种方法适用于每个线程拥有自己的资源实例的场景。
需要根据具体的使用情况和线程安全要求选择适当的方法来确保 std::shared_ptr
的线程安全性。
请注意,尽管 std::shared_ptr
的引用计数操作是线程安全的,但对于对象本身的访问并不是线程安全的。如果多个线程同时访问共享对象的成员变量或调用对象的非线程安全函数,仍然需要适当的同步机制来保证线程安全性。
参考文档
https://en.cppreference.com/w/cpp/memory/shared_ptr
https://stackoverflow.com/questions/9127816/stdshared-ptr-thread-safety-explained