memory_order_relaxed如何工作以增加智能指针中的原子引用计数? [英] How can memory_order_relaxed work for incrementing atomic reference counts in smart pointers?

查看:322
本文介绍了memory_order_relaxed如何工作以增加智能指针中的原子引用计数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下摘自Herb Sutter关于原子的演讲的代码片段:

Consider the following code snippet taken from Herb Sutter's talk on atomics:

smart_ptr类包含一个名为control_block_ptr的pimpl对象,其中包含引用计数 refs .

The smart_ptr class contains a pimpl object called control_block_ptr containing the reference count refs.

// Thread A:
// smart_ptr copy ctor
smart_ptr(const smart_ptr& other) {
  ...
  control_block_ptr = other->control_block_ptr;
  control_block_ptr->refs.fetch_add(1, memory_order_relaxed);
  ...
}

// Thread D:
// smart_ptr destructor
~smart_ptr() {
  if (control_block_ptr->refs.fetch_sub(1, memory_order_acq_rel) == 1) {
    delete control_block_ptr;
  }
}

Herb Sutter说,线程A中 refs 的增量可以使用memory_order_relaxed,因为没有人根据操作执行任何操作".现在我了解到memory_order_relaxed,如果 refs 在某些时候等于N,并且两个线程A和B执行以下代码:

Herb Sutter says the increment of refs in Thread A can use memory_order_relaxed because "nobody does anything based on the action". Now as I understand memory_order_relaxed, if refs equals N at some point and two threads A and B execute the following code:

control_block_ptr->refs.fetch_add(1, memory_order_relaxed);

然后可能会发生两个线程都看到 refs 的值为N并都将N + 1写回该值的情况.显然这是行不通的,并且应该与析构函数一样使用memory_order_acq_rel.我要去哪里错了?

then it may happen that both threads see the value of refs to be N and both write N+1 back to it. That will clearly not work and memory_order_acq_rel should be used just as with the destructor. Where am I going wrong?

考虑以下代码.

atomic_int refs = N; // at time t0. 

// [Thread 1]
refs.fetch_add(1, memory_order_relaxed); // at time t1. 

// [Thread 2]
n = refs.load(memory_order_relaxed);   // starting at time t2 > t1
refs.fetch_add(1, memory_order_relaxed);
n = refs.load(memory_order_relaxed);

在调用fetch_add之前,线程2观察到的 refs 的值是什么?是N还是N + 1?调用fetch_add之后,线程2观察到的ref的值是多少?是否必须至少为N + 2?

What is the value of refs observed by Thread 2 before the call to fetch_add? Could it be either N or N+1? What is the value of refs observed by Thread 2 after the call to fetch_add? Must it be at least N+2?

[对话网址:C ++& 2012年后-

[Talk URL: C++ & Beyond 2012 - http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2 (@ 1:20:00)]

推荐答案

模拟std::atomic的Boost.Atomic库提供了

Boost.Atomic library that emulates std::atomic provides similar reference counting example and explanation, and it may help your understanding.

总是可以使用memory_order_relaxed完成增加引用计数器的操作:对对象的新引用只能由现有引用形成,并且将现有引用从一个线程传递到另一个线程必须已经提供了所需的同步.

Increasing the reference counter can always be done with memory_order_relaxed: New references to an object can only be formed from an existing reference, and passing an existing reference from one thread to another must already provide any required synchronization.

在删除另一个线程中的对象之前,必须强制一个线程(通过现有引用)对对象进行任何可能的访问.这是通过在删除引用后执行释放"操作(通过此引用对对象的任何访问显然必须在此之前进行的),以及在删除对象之前进行的获取"操作来实现的.

It is important to enforce any possible access to the object in one thread (through an existing reference) to happen before deleting the object in a different thread. This is achieved by a "release" operation after dropping a reference (any access to the object through this reference must obviously happened before), and an "acquire" operation before deleting the object.

可以将memory_order_acq_rel用于fetch_sub操作,但是当参考计数器尚未达到零时,这将导致不必要的获取"操作,并且可能会导致性能下降.

It would be possible to use memory_order_acq_rel for the fetch_sub operation, but this results in unneeded "acquire" operations when the reference counter does not yet reach zero and may impose a performance penalty.

这篇关于memory_order_relaxed如何工作以增加智能指针中的原子引用计数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆