什么是处理器 Lock# 信号及其工作原理?

What is processor Lock# signal and how it works?

我正在读一本关于汇编(中级)的书,它提到像 xchg 这样的一些指令会自动断言处理器 LOCK# 信号。上网查了一下,是给了处理器对任何共享内存的独占权,没有具体细节。这让我想知道这项权利是如何运作的。

  1. 这是否意味着任何其他计算机设备(例如 GPU 或其他设备)都无法访问内存。实际上,其他设备可以直接与 RAM 对话,而无需先通过 CPU。
  2. 处理器如何知道它处于此锁定状态,例如它是否保存在控件或 rflags 寄存器中,或者因为我看不到在具有多核时此操作如何工作 CPU。
  3. 我访问的网站说锁定任何共享内存。这是否意味着在此锁定期间整个 RAM 被锁定或仅锁定执行指令的内存页(或部分内存而不是全部)。

基本问题是有些指令读取内存,修改读取的值,然后写入新值;如果内存的内容在读取和写入之间发生变化,(某些)并行代码可能会以不一致的状态结束。

一个很好的例子是一个 CPU 做 inc dword [foo] 而另一个 CPU 做 dec dword [foo]。在两条指令(在两个 CPUs 上)执行后,值应该与原来的值相同;但是两个 CPU 都可以读取旧值,然后两个 CPU 都可以修改它,然后两个 CPU 都可以写入它们的新值;导致该值比您预期的高 1 或低 1。

解决方案是使用 #lock 信号来防止其他任何东西同时访问同一块内存。例如。第一个 CPU 会声明 #lock 然后执行 read/modify/write,然后取消声明 #lock;其他任何东西都会看到 #lock 被断言并且必须等到 #lock 被取消断言才能进行任何内存访问。换句话说,它是一种简单的互斥形式(类似于自旋锁,但在硬件中)。

当然,“其他一切都必须等待”会产生性能成本;所以它主要只在软件明确请求时才完成(例如 lock inc dword [foo] 而不是 inc dword [foo])但在某些情况下它是隐式完成的 - xchg 当操作数使用内存时的指令,并更新CPU 使用的某些表中的 dirty/accessed/busy 标志(用于分页和 GDT/LDT/IDT 条目)。还;后来(我认为是 Pentium Pro?),该行为被优化以与缓存一致性协议一起使用,因此如果可以将缓存行置于独占状态,则 #lock 不会被断言。

注意:过去有 2 个 CPU 错误(Intel Pentium“0xF00F”错误和 Cyrix“Coma”错误),其中 CPU 可以被欺骗断言 #lock 发出信号并且从不取消断言它;导致整个系统锁定,因为没有任何东西可以访问任何内存。

  1. Does this mean that any other computer device like GPU or something else can't have access to memory for example. Actually can other devices talk directly to RAM without passing first on the CPU.

是的。如果 #lock 被断言(这不包括较新的 CPU 可以将缓存行置于独占状态的情况);任何访问内存的东西都必须等待 #lock 被取消断言。

注意:大多数现代设备 can/do 直接访问内存(传输数据 to/from RAM 而无需使用 CPU 传输数据)。

  1. How does the processor know that it's in this locked state is it saved in a control or rflags register for example or what since I can't see how this operation works when having multicore CPU.

它没有保存在任何寄存器的内容中。它实际上是公共汽车上的电子信号或 link。举一个极其简单的例子;假设总线有 32 条“地址”线,32 条“数据”线,外加一条 #lock 线;其中“断言 #lock”表示 #lock 线上的电压从 0 伏到 3.3 伏。当任何东西想要读取或写入内存时(在尝试更改“地址”线或“数据”线上的电压之前),它会检查 #lock 线上的电压是否为 0 伏。

注意:真正的总线要复杂得多,需要一些其他信号(例如传输方向、避免冲突、“I/O端口或物理内存”等);现代总线使用串行通道而不是并行线;现代系统使用“点对点 links”,而不是“所有事物共享的公共总线”。

  1. The websites I visited said lock any shared memory. does this mean that during this lock period the whole RAM is locked or just the memory page(or part of memory not all of it) that the instruction is performed on.

不如说公交车被锁了;一切都必须使用总线来访问内存(当总线被锁定时,没有其他任何东西可以使用总线,即使当其他东西试图将总线用于与内存无关的事情时 - 例如发送 IRQ 到CPU).

当然(由于积极的性能优化 - 主要是“如果缓存行可以置于独占状态而不是”优化)更好的是说硬件可以做任何感觉只要结果表现得好像有一个共享总线被锁定(即使没有共享总线并且实际上没有任何东西被锁定)。

注意:80x86 支持未对齐的访问(例如,您可以 lock inc dword [address] 访问可以跨越边界),如果内存访问跨越边界,则 CPU 需要组合 2 个或更多部分(例如,一个缓存行末尾的几个字节和下一个缓存行开头的几个字节)。现代虚拟内存意味着如果虚拟地址跨越页面边界,CPU 需要访问 2 个不同的虚拟页面,这些页面可能具有“极其不相关”的物理地址。如果理论上的 CPU 试图实现独立锁(每个内存区域不同的锁),那么它还需要支持断言多个锁信号。这可能会导致死锁 - 例如一个 CPU 锁定“内存页 1”,然后尝试锁定“内存页 2”(但不能,因为它已被锁定);而另一个 CPU 锁定“内存页 2”,然后尝试锁定“内存页 1”(但不能,因为它已被锁定)。要修复理论上的 CPU 必须使用“全局锁排序”——始终以特定顺序断言锁。最终结果将是大量的复杂性(增加的复杂性可能会比节省的性能成本更高)。