Linux Intel 指令的 LOCK 前缀。重点是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11065675/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
LOCK prefix of Intel instruction. What is the point?
提问by Sean
I read the Intel manual and found there is a lock prefix for instructions, which can prevent processors writing to the same memory location at the same time. I am quite excited about it. I guess it could be used as hardware mutex. So I wrote a piece of code to have a shot. The result is quite frustrating. The lock does not support MOV or LEA instructions. The manual says LOCK only supports ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, and XCHG. What is more, if the LOCK prefix is used with one of these instructions and the source operand is a memory operand, an undefined opcode exception (#UD) may be generated.
我阅读了英特尔手册,发现指令有一个锁定前缀,可以防止处理器同时写入同一内存位置。我对此感到非常兴奋。我想它可以用作硬件互斥锁。所以我写了一段代码来试一试。结果相当令人沮丧。该锁不支持 MOV 或 LEA 指令。手册上说LOCK只支持ADD、ADC、AND、BTC、BTR、BTS、CMPXCHG、CMPXCH8B、DEC、INC、NEG、NOT、OR、SBB、SUB、XOR、XADD和XCHG。此外,如果 LOCK 前缀与这些指令之一一起使用并且源操作数是内存操作数,则可能会生成未定义的操作码异常 (#UD)。
I wonder why so many limitations, so many restrictions make LOCK seem useless. I cannot use it to guarantee a general write operation not have dirty data or other problems caused by parallelism.
我想知道为什么这么多限制,这么多限制让 LOCK 看起来毫无用处。我不能用它来保证一般的写操作没有脏数据或其他由并行引起的问题。
E.g. I wrote code ++(*p) in C. p is pointer to a shared memory. The corresponding assembly is like:
例如,我在 C 中编写了代码 ++(*p)。p 是指向共享内存的指针。对应的程序集是这样的:
movl 28(%esp), %eax
movl (%eax), %eax
leal 1(%eax), %edx
movl 28(%esp), %eax
movl %edx, (%eax)
I added "lock" before "movl" and "leal", but the processor complains "Invalid Instruction". :-( I guess the only way to make the write operations serialized is to use software mutex, right?
我在“movl”和“leal”之前添加了“lock”,但处理器抱怨“无效指令”。:-( 我想使写操作序列化的唯一方法是使用软件互斥锁,对吗?
采纳答案by NPE
I certainly would not call lock
useless. lock cmpxchg
is the standard way to perform compare-and-swap, which is the basic building block of many synchronization algorithms.
我当然不会说lock
没用。lock cmpxchg
是执行compare-and-swap的标准方法,它是许多同步算法的基本构建块。
Also, see fetch-and-add.
另请参阅fetch-and-add。
回答by Ignacio Vazquez-Abrams
The purpose of lock
is to make operations atomic, not serialized. In this way the CPU cannot be preempted before the operation takes effect.
的目的lock
是使操作原子化,而不是序列化。这样,在操作生效之前,CPU 是无法被抢占的。
回答by ob_dev
It is useful when, on a multiprocessor machine, there are two concurrent processes that are using the same data but they can't modify it simultaneously.
当在多处理器机器上有两个并发进程使用相同的数据但它们不能同时修改它时,它很有用。
When one of the processes is modifying the data, it uses lock on the modifying instruction so that, when the second process tries to modify it, it has to wait for the first one to finish its job before being able to do its own on its turn.
当其中一个进程正在修改数据时,它对修改指令使用锁,这样当第二个进程尝试修改它时,它必须等待第一个进程完成其工作才能自行完成转动。
I hope this will help a bit.
我希望这会有所帮助。
回答by Jirka Hanika
The x86 processors are known for a hairy design with lots of features, lots of rules, and even more exceptions to all those rules. This is related to the long history to the family.
x86 处理器以毛茸茸的设计而著称,它具有许多功能、许多规则,甚至还有所有这些规则的更多例外。这与家族的悠久历史有关。
When compilers or people are using LOCK
, they are always using it with all its limitations, often on data specially introduced to perform synchronization between threads, as opposed to application data that the algorithms eventually manipulate. One then adapts the thread synchronization protocols to what LOCK
can do for them, rather than vice versa.
当编译器或人们使用 时LOCK
,他们总是使用它的所有限制,通常是专门引入用于在线程之间执行同步的数据,而不是算法最终操作的应用程序数据。然后使线程同步协议适应LOCK
可以为它们做的事情,而不是相反。
The general type of instruction you seem to look for is called memory barriers. Indeed, x86 has several "modern" instructions from this family (MFENCE, LFENCE, SFENCE). They are full fence, load fence, and store fence, respectively. However, their importance in the instruction set is limited to SSE, because Intel guarantees serialization of writes on the traditional part of the instruction set, and that is pretty much the reason why this aged architecture is quite an easy target for multithreaded programming.
您似乎在寻找的一般指令类型称为内存屏障。事实上,x86 有几个来自这个家族的“现代”指令(MFENCE、LFENCE、SFENCE)。它们分别是全围栏、装载围栏和存储围栏。然而,它们在指令集中的重要性仅限于SSE,因为英特尔保证指令集传统部分的写入序列化,这几乎就是为什么这种陈旧的架构很容易成为多线程编程的目标的原因。
See also this answerfor more info.
另请参阅此答案以获取更多信息。
回答by fuz
In the example you provide, you can use a lock
prefix with an inc
instruction like this (assuming p
is located in %eax
):
在您提供的示例中,您可以将lock
前缀与这样的inc
指令一起使用(假设p
位于%eax
):
lock inc (%eax)
In more general cases, you have to use locks though.
在更一般的情况下,您必须使用锁。