4

我在堆上分配了一些很少修改但需要快速读取访问的数据结构。一个示例是在堆上分配的结构,许多线程以只读方式非常频繁地访问该结构。auto_ptr需要定期重写此结构并避免锁定争用,重写它并快速与结构的新auto_ptr实例交换指针。

我从CopyOnWriteArrayListJava 中得到了这个想法,并希望在 C++ 中执行类似的性能。

4

2 回答 2

8

std::auto_ptrreset()在调用非常量成员(如您所建议的)时没有任何线程安全保证。此外,std::unique_ptr您应该考虑作为替代的auto_ptras也没有auto_ptr被有效地弃用。

std::shared_ptr 确实提供了这样的线程安全保证。

您通常可以保证shared_ptr引用计数是以原子方式操作的,这意味着在创建 a 的副本时您可以安全地避免数据竞争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

这样做很重要,原因有两个。

  1. atomic_* 操作为您提供了一种线程安全的方式来制作共享指针的副本。
  2. 制作副本意味着当全局共享指针发生更改时,您的副本仍然指向旧字符串,因此您的代码不必担心它所操作的数据会在它不期望的情况下发生更改。

现在,重要的是要注意在 a 上使用线程安全操作shared_ptr不会为其指向的类型提供任何线程安全性。您始终必须注意以线程安全的方式使用指向的对象。

于 2013-01-05T19:18:19.437 回答
2

您可以使用 reset() 即时重新分配 auto_ptr,顺便说一下,它会破坏以前指向的对象实例。

但是,auto_ptr 已被 unique_ptr 弃用,它有一个 swap() 函数,似乎有点坚持你正在寻找的东西。

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

于 2013-01-05T19:17:22.247 回答