在多线程环境中使用auto_ptr交换对象是安全的,不需要锁定
Safe to use auto_ptr to swap objects without locking in multithreaded environment?
我在堆上分配了一些数据结构,它们很少被修改,但需要快速读取访问。一个例子是在堆上分配的结构体,许多线程非常频繁地以只读方式访问它。这个结构体需要周期性地重写,为了避免锁争用,我想知道使用auto_ptr
是否安全,基本上允许已经获得引用的线程继续处理直到它们完成,但允许编写器复制结构体,重写它并快速交换指针与结构体的新auto_ptr
实例。
我从Java的CopyOnWriteArrayList
中得到了这个想法,并希望在c++中执行类似的性能。
std::auto_ptr
在调用非const成员(如reset()
)时没有任何线程安全保证。此外,std::unique_ptr
也没有,你应该考虑作为auto_ptr
的替代品,因为auto_ptr
已经被有效地弃用了。
std::shared_ptr
提供了这样的线程安全保证。
对于shared_ptr
,您通常可以保证的是引用计数以原子方式进行操作,这意味着在创建shared_ptr
的副本时,如果当前没有人正在修改shared_ptr
,则不会出现数据竞争。
考虑以下shared_ptr
用例。你有一个全局的shared_ptr<string> sharedString;
,它当前指向std::string
的一个实例。对于许多线程来说,调用get()
来获取指向该字符串的指针是安全的。它们也可以创建自己的共享指针,如:shared_ptr<string> myString = sharedString;
,前提是没有人改变共享指针指向的对象。
现在,让我们回过头来修复示例中存在的竞争条件。当需要更改全局共享指针指向的内容时,线程可能正在创建它的副本——这是一个问题,因为它可能使副本处于不一致的状态。因此,我们必须确保我们自动地修改和复制它。
幸运的是,shared_ptr
提供了许多c++ 11原子操作的专门化:atomic_load
、atomic_store
和atomic_exchange
。
复制shared_ptr
时使用atomic_load
,更新shared_ptr
时使用atomic_store
。
这样做很重要,原因有二。
- atomic_*操作提供了一种线程安全的方式来复制共享指针。
- 复制意味着当全局共享指针被改变时,你的副本仍然指向旧的字符串,所以你的代码不必担心当它不期望它改变时它所操作的数据。
shared_ptr
上使用线程安全操作并不为它所指向的类型提供任何线程安全。您必须始终注意所指向的对象是以线程安全的方式使用的。
可以使用reset()动态地重新赋值auto_ptr对象,顺便说一下,它会破坏先前指向的对象实例。
然而,auto_ptr被unique_ptr弃用了,unique_ptr有一个swap()函数,似乎可以满足你的要求。
请记住,这些类不是线程安全的。
- 在什么条件下使用 std::memcpy 在对象之间复制是安全的?
- 线程调用的函数对对象删除是否安全?
- 将对象的字节复制到数组并再次复制回来是否安全
- std::memmove在同一对象之间是否始终安全
- asio 链对象线程安全吗?
- 同时调用 ASIO 对象的 API 是否安全?
- 如何将带有缓冲区的对象从插件发送到节点线程安全
- 对于琐碎的对象,在"this"上调用新放置是否安全?
- 单一实例对象是否通过线程安全返回shared_ptr
- 编译器在 const ref 类型参数上使用临时对象时是否应该警告不安全的行为?
- 我怎么知道C++编译器是否制作线程安全的静态对象代码
- 在容器中存储指向对象的指针时的线程安全
- 将对象(如 STL 对象)传入和传出静态库是否安全
- 原子对象在普通对象安全的任何上下文中都是不安全的
- 编写安全包装类以管理用户定义对象的指针
- 链接 gcc 6、gcc 7 和 gcc 8 对象是否安全?
- 关于"pure"函数对象的常量和线程安全
- C++安全对象删除
- 通过线程安全容器传递非线程安全对象
- c++11中的线程安全对象状态操作