为什么std :: atomic中的所有成员函数都带有volatile和不带volatile?

The*_*Vee 8 c++ volatile c++11

我注意到std::atomic<T>类型的大多数成员函数被声明两次,一次使用volatile修饰符,一次没有(示例)).我检查了G ++标准库实现的源代码,我发现所有这些都是完全重复的,例如,

bool
load(memory_order __m = memory_order_seq_cst) const noexcept
{ return _M_base.load(__m); }

bool
load(memory_order __m = memory_order_seq_cst) const volatile noexcept
{ return _M_base.load(__m); }
Run Code Online (Sandbox Code Playgroud)

我找不到任何示例,其中volatile变体的行为与非行为不同volatile,返回类型或该类型的任何内容都不同.

这是为什么?我认为volatile也可以在不是的对象中调用成员函数volatile.所以声明和定义std::atomic::load(...) const volatile noexcept等应该足够了.

更新:

根据评论我的问题基本归结为:你能提供一个例子,其中一些使用volatile实例(不一定是std::atomic)的调用会在以下两种情况下生成不同的程序集,

  1. 每个成员函数在有和没有相同的主体时出现volatile,

  2. 只有volatile变体存在?

这,假设编译器可以执行标准允许的任何优化(或者只是最高优化级别).

Yuk*_*uki 1

也许这一切都源于现状volatile,请参阅这个答案。由于与通常的应用程序开发相比,用例相当少,这就是为什么通常没有人关心的原因。我假设您没有任何实际场景想知道是否应该应用这些易失性重载。然后我会尝试举一个你可能需要这些的例子(不要认为它太真实)。

volatile std::sig_atomic_t status = ~SIGINT;
std::atomic<int> shareable(100);

void signal_handler(int signal)
{
  status = signal;
}

// thread 1
  auto old = std::signal(SIGINT, signal_handler);
  std::raise(SIGINT);
  int s = status;
  shareable.store(10, std::memory_order_relaxed);
  std::signal(SIGINT, old);

// thread 2
  int i = shareable.load(std::memory_order_relaxed);
Run Code Online (Sandbox Code Playgroud)

memory_order_relaxed保证原子性和修改顺序一致性,无副作用。volatile不能重新排序而产生副作用。然后我们在线程 2 中可以得到shareable等于 10,但状态仍然不是SIGINT。但是,如果将类型限定符设置为volatileof shareable,则必须保证这一点。为此,您需要对成员方法进行volatile限定。

你为什么要做这样的事?我可能会想到的一种情况是,您有一些使用volatile基于旧内容的旧代码,并且由于某种原因您无法修改它。很难想象,但我想可能需要在内联汇编之间有某种保证的atomic顺序volatile。恕我直言,底线是,只要有可能,您就可以使用新的原子库而不是volatile对象,如果存在一些volatile您无法删除的对象,并且您想使用atomic对象,那么您可能需要volatile限定符atomic对象具有正确的排序保证,为此您需要重载。

更新

但如果我想要的只是让原子类型既可用作易失性又可用作非易失性,为什么不直接实现前者呢?

struct Foo {
    int k;
};

template <typename T>
struct Atomic {
  void store(T desired) volatile { t = desired; }
  T t;
};

int main(int i, char** argv) {
    //error: no viable overloaded '='
    // void store(T desired) volatile { t = desired; }
  Atomic<Foo>().store(Foo());
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

和其他操作也是如此load,因为这些通常不是需要复制运算符和/或复制构造函数(也可以volatile或不volatile)的简单实现。