在多线程环境中使用auto_ptr交换对象是安全的,不需要锁定

Safe to use auto_ptr to swap objects without locking in multithreaded environment?

本文关键字:安全 对象 锁定 不需要 交换 ptr 环境 多线程 auto      更新时间:2023-10-16

我在堆上分配了一些数据结构,它们很少被修改,但需要快速读取访问。一个例子是在堆上分配的结构体,许多线程非常频繁地以只读方式访问它。这个结构体需要周期性地重写,为了避免锁争用,我想知道使用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_loadatomic_storeatomic_exchange

复制shared_ptr时使用atomic_load,更新shared_ptr时使用atomic_store

这样做很重要,原因有二。

    atomic_*操作提供了一种线程安全的方式来复制共享指针。
  1. 复制意味着当全局共享指针被改变时,你的副本仍然指向旧的字符串,所以你的代码不必担心当它不期望它改变时它所操作的数据。
现在,重要的是要注意,在shared_ptr上使用线程安全操作并不为它所指向的类型提供任何线程安全。您必须始终注意所指向的对象是以线程安全的方式使用的。

可以使用reset()动态地重新赋值auto_ptr对象,顺便说一下,它会破坏先前指向的对象实例。

然而,auto_ptr被unique_ptr弃用了,unique_ptr有一个swap()函数,似乎可以满足你的要求。

请记住,这些类不是线程安全的。