【问题标题】:InterlockedExchange and memory alignmentInterlockedExchange 和内存对齐
【发布时间】:2010-10-27 06:41:30
【问题描述】:

我很困惑微软说 InterlockedExchange 需要内存对齐,但是英特尔文档说 LOCK 不需要内存对齐。 我错过了什么,还是什么? 谢谢

来自 Microsoft MSDN 库

平台 SDK:DLL、进程和线程 联锁交流

Target 参数指向的变量必须在 32 位边界上对齐;否则,此函数将在多处理器 x86 系统和任何非 x86 系统上运行不可预测。

来自英特尔软件开发人员手册;

  • LOCK 指令 使处理器的 LOCK# 信号在伴随指令的执行期间被断言(将指令转换为原子指令)。在多处理器环境中,LOCK# 信号确保处理器在断言信号时独占使用任何共享内存

    LOCK 前缀的完整性不受内存字段对齐的影响。 观察到任意未对齐字段的内存锁定。

  • P6 和最新处理器系列中的内存排序

    锁定指令有一个总顺序。

  • 软件控制的总线锁定

    总线锁的完整性不受内存字段对齐的影响。 更新整个操作数所需要的尽可能多的总线周期都遵循 LOCK 语义。但是,建议锁定访问在其自然边界上对齐,以获得更好的系统性能: • 8 位访问的任何边界(锁定或其他)。 •锁定字访问的16 位边界。 • 锁定双字访问的32 位边界。 • 锁定四字访问的 64 位边界。

【问题讨论】:

标签: multithreading winapi x86 interlocked


【解决方案1】:

曾几何时,Microsoft 在 x86 以外的处理器(例如 MIPS、PowerPC 和 Alpha)上支持 WindowsNT。这些处理器都需要对齐它们的互锁指令,因此微软在他们的规范中提出了要求,以确保这些原语可以移植到不同的架构。

【讨论】:

  • x64 模式也需要在联锁操作上对齐
  • @Rom:不,它没有,x86-64 仍然“仅”需要与lock-prefixed 指令对齐性能。请参阅alignment requirements for atomic x86 instructions 以获取英特尔第 3 卷手册的引用。拆分锁的性能损失非常高,但这不是正确性问题。
【解决方案2】:

即使锁定前缀不需要对齐内存,并且可能用于实现 InterlockedExchange() 的 cmpxchg 操作也不需要对齐,但如果操作系统已启用对齐检查,则 cmpxchg 将引发对齐检查使用未对齐的操作数执行时出现异常 (AC)。检查 cmpxchg 和类似的文档,查看保护模式异常列表。我不确定 Windows 是否启用对齐检查,但我不会感到惊讶。

【讨论】:

  • 应该这样吗? : "cmpxchg 操作 ... 不需要 是否需要对齐"
  • 如果没有memcpy 故障,您可能无法启用 AC 标志,因此这不是一个真正合理的情况/用例。现代编译器发出的代码也会执行潜在的未对齐加载,例如加载多个 charshort 结构成员,即使它们不一定对齐。默认情况下,Windows 肯定不会启用 AC。
【解决方案3】:

嘿,I 回答了一些与此相关的问题,也请记住;

  1. NO 字节级别 InterlockedExchange IS 16 位 InterlockedExchange。
  2. 您提到的文档差异可能只是一些文档疏忽。
  3. 如果您想要进行字节/位级别的原子访问,使用现有的内部函数 Interlocked[And8|Or8|Xor8] 有很多方法可以做到这一点
  4. 您进行高性能锁定的任何操作(使用您所讨论的机器代码)都不应未对齐(性能反模式
  5. xchg(具有隐式 LOCK 前缀的优化指令,由于能够缓存锁定并避免对主存储器的完全总线锁定而进行了优化)。 CAN 进行 8 位联锁操作。

我差点忘了,从 Intel 的 TBB 那里,他们定义了 Load/Store 8bit,不使用隐式或显式锁定(在某些情况下);

.code 
    ALIGN 4
    PUBLIC c __TBB_machine_load8
__TBB_machine_Load8:
    ; If location is on stack, compiler may have failed to align it correctly, so we do dynamic check.
    mov ecx,4[esp]
    test ecx,7
    jne load_slow
    ; Load within a cache line
    sub esp,12
    fild qword ptr [ecx]
    fistp qword ptr [esp]
    mov eax,[esp]
    mov edx,4[esp]
    add esp,12
    ret

EXTRN __TBB_machine_store8_slow:PROC
.code 
    ALIGN 4
    PUBLIC c __TBB_machine_store8
__TBB_machine_Store8:
    ; If location is on stack, compiler may have failed to align it correctly, so we do dynamic check.
    mov ecx,4[esp]
    test ecx,7
    jne __TBB_machine_store8_slow ;; tail call to tbb_misc.cpp
    fild qword ptr 8[esp]
    fistp qword ptr [ecx]
    ret
end

无论如何,希望至少能为您解决一些问题。

【讨论】:

【解决方案4】:

我不明白你的英特尔信息来自哪里。

对我来说,很明显英特尔非常关心对齐和/或跨越缓存线。

例如,在 Core-i7 处理器上,您仍然必须确保您的数据不会跨越缓存线,否则不能保证操作是原子的。

在第 3-I 卷,系统编程,对于 x86/x64 英特尔明确指出:

8.1.1 保证原子操作

Intel486 处理器(以及之后的更新处理器)保证以下 基本的内存操作将始终以原子方式执行:

  • 读取或写入一个字节
  • 读取或写入在 16 位边界上对齐的字
  • 读取或写入在 32 位边界上对齐的双字

奔腾处理器(以及之后的更新处理器)保证以下 额外的内存操作将始终以原子方式执行:

  • 读取或写入在 64 位边界上对齐的四字
  • 对适合 32 位数据总线的未缓存内存位置进行 16 位访问

P6 系列处理器(以及之后的更新处理器)保证以下 额外的内存操作将始终以原子方式执行:

  • 对适合缓存的缓存内存进行未对齐的 16、32 和 64 位访问 行

对跨缓存行和页面边界拆分的可缓存内存的访问 英特尔酷睿 2 双核、英特尔® 凌动™、英特尔酷睿不保证是原子的 Duo、Pentium M、Pentium 4、Intel Xeon、P6 系列、Pentium 和 Intel486 处理器。 英特尔酷睿 2 双核、英特尔凌动、英特尔酷睿双核、奔腾 M、奔腾 4、英特尔至强、 和 P6 系列处理器提供允许外部存储器的总线控制信号 使拆分访问原子化的子系统;然而,非对齐的数据访问将 严重影响处理器的性能,应该避免。

【讨论】:

  • 此答案中提供的信息似乎与“基本内存操作”有关,而问题的上下文是 锁定 操作。
猜你喜欢
  • 2010-11-07
  • 1970-01-01
  • 2013-06-27
  • 2017-11-15
  • 2012-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多