【问题标题】:Atomic Assignment Operator原子赋值运算符
【发布时间】:2013-07-08 21:05:49
【问题描述】:

我正在实现一个非常轻量级的原子包装器,作为 Windows 的 C++ 中原始数据类型的学习练习,我有一些关于实现赋值运算符的简单问题。考虑以下两种实现:

// Simple assignment
Atomic& Atomic::operator=(const Atomic& other)
{
    mValue = other.mValue;
    return *this;
}

// Interlocked assignment
Atomic& Atomic::operator=(const Atomic& other)
{
    _InterlockedExchange(&mValue, other.mValue);
    return *this;
}

假设 mValue 是正确的类型,并且 Atomic 类将其作为成员。

  1. 线程安全的赋值运算符是否需要_InterlockedExchange,还是简单的实现足以保证线程安全?
  2. 如果简单赋值是线程安全的,那么是否还需要为这个类实现赋值运算符?编译器默认值就足够了,不是吗?
  3. 如果简单赋值在 Windows 中是线程安全的,那么它在其他平台中是否也是线程安全的?是否需要等效于 _InterlockedExchange 才能保证其他平台上的线程安全?

【问题讨论】:

    标签: c++ winapi atomic assignment-operator


    【解决方案1】:

    if mValue 是原始类型(在 32 位 CPU 上最多 32 位宽,在 64 位 CPU 上最多 64 位宽),和 您在 x86 CPU(32 位或 64 位模式)上运行并且您不会手动错位数据,然后保证内存读取/写入是原子的。

    这本身并不意味着编译器不会重新排序内存访问,甚至完全优化它,但 CPU 确实保证任何与这些大小的数据对齐良好的读/写都是原子的。

    但是,请注意,我说的是原子性,而不是线程安全,因为“线程安全”取决于使用代码的上下文。

    【讨论】:

    • 如果这些条件不成立,我需要_InterlockedExchange(或其他系统上的等效项),还是有更合适的原子函数?
    • 只有std::atomic更合适。
    • 如果这些条件不成立,则取决于哪些条件为真。 _InterlockedExchange 不是魔法。它是围绕 CPU 特定指令的包装器,保证是原子的。如果这样的指令不存在,那么_InterlockedExchange 无能为力
    【解决方案2】:

    C++ 原子类型处理三个 问题。首先,在读写过程中可能会发生线程切换,导致数据乱码;这被称为“撕裂”。其次,每个处理器都有自己的数据缓存,在一个线程中写入值并不一定会更新另一个处理器缓存中的值;这是“陈旧数据”。第三,如果结果不违反各种规则,编译器可以重新排序指令以提高效率;如果你不告诉它数据是在线程之间共享的,它可能会做一些让你吃惊的事情。

    使用std::atomic(或用于确保原子性的各种特定于实现的机制)可以处理所有三个问题。 没有充分的理由绕过它们;库和编译器编写者几乎可以肯定比您更了解如何生成可正常工作的高效代码。

    【讨论】:

      【解决方案3】:
      1. 这取决于mValue 的大小和对齐方式,这进一步取决于Atomic 对象的对齐方式。通常,如果大小等于 CPU 寄存器的大小并且正确对齐,则写入是原子的。 (示例:与 32 位 CPU 上的 32 位边界对齐的 32 位数据类型将以原子方式写入。在这种情况下,不保证 64 位数据类型的原子性。)
      2. 正确,编译器默认实现将与您给出的“简单赋值”示例相同,假设 mValue 是唯一的实例数据成员。
      3. 通常,是的,因为这更多是 CPU 和体系结构的功能,而不是特定的操作系统。如果mValue 的写入不是原子的,您将需要一个类似的构造。 (例如,请参阅GCC documentation regarding built-in atomic operations。)

      【讨论】:

        猜你喜欢
        • 2016-04-25
        • 2011-08-02
        • 2019-10-06
        • 2011-11-16
        • 2015-12-14
        • 2013-11-30
        • 2015-10-02
        • 1970-01-01
        • 2015-09-27
        相关资源
        最近更新 更多