【问题标题】:C++0x | Why std::atomic overloads each method with the volatile-qualifier?C++0x |为什么 std::atomic 使用 volatile 限定符重载每个方法?
【发布时间】:2011-06-19 17:50:40
【问题描述】:

当前草案的以下摘录说明了我的意思:

namespace std {
    typedef struct atomic_bool {
        bool is_lock_free() const volatile;
        bool is_lock_free() const;
        void store(bool, memory_order = memory_order_seq_cst) volatile;
        void store(bool, memory_order = memory_order_seq_cst);
        bool load(memory_order = memory_order_seq_cst) const volatile;
        bool load(memory_order = memory_order_seq_cst) const;
        operator bool() const volatile;
        operator bool() const;
        bool exchange(bool, memory_order = memory_order_seq_cst) volatile;
        bool exchange(bool, memory_order = memory_order_seq_cst);
        bool compare_exchange_weak(bool&, bool, memory_order, memory_order) volatile;
        bool compare_exchange_weak(bool&, bool, memory_order, memory_order);
        bool compare_exchange_strong(bool&, bool, memory_order, memory_order) volatile;
        bool compare_exchange_strong(bool&, bool, memory_order, memory_order);
        bool compare_exchange_weak(bool&, bool, memory_order = memory_order_seq_cst) volatile;
        bool compare_exchange_weak(bool&, bool, memory_order = memory_order_seq_cst);
        bool compare_exchange_strong(bool&, bool, memory_order = memory_order_seq_cst) volatile;
        bool compare_exchange_strong(bool&, bool, memory_order = memory_order_seq_cst);
        atomic_bool() = default;
        constexpr atomic_bool(bool);
        atomic_bool(const atomic_bool&) = delete;
        atomic_bool& operator=(const atomic_bool&) = delete;
        atomic_bool& operator=(const atomic_bool&) volatile = delete;
        bool operator=(bool) volatile;
    } atomic_bool;
}

易失性是可传递的。因此,您不能从易失性对象调用非易失性成员函数。另一方面,允许从非易失性对象调用易失性成员函数。

那么,原子类中的 volatile 和 non-volatile 成员函数在实现上有什么区别吗?换句话说,非易失性重载有必要吗?

【问题讨论】:

  • @GMan:因为否则无法对易失性数据调用函数。 ;)
  • @jalf:哈,是的,但是由于类型本身进行的操作是原子的(因此是可观察的),我们为什么要创建volatile atomic<>?我想我错过了一些重要的东西。
  • @GMan:但为什么不允许呢?假设您有一个atomic<> 作为另一个结构的成员,并且创建了一个volatile 实例?然后它的所有成员也将隐含为volatile,并且没有volatile 重载,您闪亮的新atomic 类将毫无用处。 :)
  • @GMan:完全正确。如果对象 表现 就好像它是 volatile 一样,那么如果我添加 volatile 限定符,它也应该可以工作,不是吗?您是否还会争辩说“如果该类在语义上仍然是恒定的,那么标记类const 的成员是没有意义的”?没有区别,除了允许类在相关限定符存在的上下文中继续工作
  • @jalf:“如果对象表现得好像它是 volatile 的,那么如果我添加 volatile 限定符,它也应该工作,不是吗”也许,但我的问题是为什么我们甚至需要 支持,如果添加 they 关键字无论如何都没有区别。您的 const 示例非常适合说明为什么我们需要在成员函数上使用 const,但是如果我们有一个本质上是 const 的类型呢? (例如,std::integral_constant。)创建 const 的实例有什么好处?

标签: c++ c++11 volatile member-functions qualifiers


【解决方案1】:

我认为 volatile 重载是出于效率原因而存在的。易失性读写在本质上比 C++0x 中的非易失性读写更昂贵,因为内存模型提出了一些严格的要求,以防止缓存易失性变量的值。如果所有函数都只标记为 volatile,则代码不一定会进行某些优化,否则会提高性能。有了这种区别,编译器就可以在可能的情况下优化非易失性读写,同时在需要易失性读写时优雅地降级。

【讨论】:

  • volatile 限定符只是阻止编译器优化。此外,据我所知,应用于成员函数的 volatile 限定符仅允许从 volatile 对象调用此方法,并且不会影响生成的代码。
  • @FrEEzE2046- 在 C++0x 中,volatile 的定义更加严格,实际上不仅仅意味着“不优化”。此外,成员函数上的 volatile 修饰符更准确的含义是 this 指针是 volatile,因此函数中发生的对成员变量的任何访问都将隐式变为 volatile
  • 好的,这意味着在调用 volatile 成员函数时,对对象的任何访问都不会被优化? (易失性描述为:“对易失性对象的访问严格按照抽象机的规则进行评估。”)
  • +1 是否添加非易失版本是早期草稿中的未决问题之一。它是根据编译器实现者的要求而专门添加的。见open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2925.html#LWG1147
【解决方案2】:

首先,创建一个 volatile std::atomic 听起来是多余的。实际上,我可以想象一个有用的情况。假设我们有一个要操作的固定设备(内存)地址。由于 std::atomic_xxx 类以及 std::atomic 模板类的大小应该与其对应的内置类型大小相同,您可能希望同时处理这两者: Performing atomic operations with control over内存排序并确保对我们的原子对象的访问永远不会优化。因此,我们可以声明如下:

std::atomic<long> volatile* vmem_first4 = reinterpret_cast<std::atomic<long> volatile*>(0xxB8000);

【讨论】:

  • 标准明确指出atomic&lt;T&gt; 的大小可能与等效的T 不同
  • "原子地址类型的表示不需要与其对应的常规类型具有相同的大小。它应该尽可能具有相同的大小。"所以, volatile atomic 对我来说似乎没用。
猜你喜欢
  • 2019-12-27
  • 1970-01-01
  • 2011-10-01
  • 1970-01-01
  • 2012-10-19
  • 2016-03-27
  • 2021-06-08
  • 2021-06-21
  • 1970-01-01
相关资源
最近更新 更多