提问者:小点点

Intel指令的LOCK前缀。有什么意义?


我读了英特尔手册,发现指令有一个锁前缀,可以防止处理器同时写入相同的内存位置。我对此相当兴奋。我猜测它可以用作硬件互斥锁。所以我写了一段代码来试一试。结果相当令人沮丧。锁不支持MOV或LEA指令。手册说LOCK只支持ADD、ADC、AND、BTC、BTR、BTS、CMPXCHG、CMPXCH8B、DEC、INC、NEG、Not、OR、SBB、SUB、XOR、XADD和XCHG。此外,如果LOCK前缀与这些指令之一一起使用,并且源操作数是内存操作数,则可能会生成未定义的操作码异常(#UD)。

我想知道为什么这么多限制,这么多限制让LOCK看起来毫无用处。我不能用它来保证一般的写操作不会有脏数据或并行引起的其他问题。

例如。我用C编写了代码(*p)。p是指向共享内存的指针。相应的程序集如下所示:

movl    28(%esp), %eax
movl    (%eax), %eax
leal    1(%eax), %edx
movl    28(%esp), %eax
movl    %edx, (%eax)

我在“movl”和“leal”之前添加了“lock”,但是处理器抱怨“无效指令". :-( 我想使写入操作序列化的唯一方法是使用软件互斥锁,对吗?


共3个答案

匿名用户

我当然不会称lock无用。lock cmpxchg是执行比较和交换的标准方式,这是许多同步算法的基本构建块。

另外,请参阅获取和添加。

匿名用户

lock的目的是使操作原子化,而不是序列化。这样在操作生效之前就不能抢占CPU。

匿名用户

x86处理器以其多毛的设计而闻名,它有许多功能、许多规则,甚至所有这些规则都有更多的例外。这与该家族的悠久历史有关。

当编译器或人们使用LOCK时,他们总是使用它的所有限制,通常是在专门用于执行线程之间同步的数据上,而不是算法最终操作的应用程序数据上。然后,一个人调整线程同步协议以适应LOCK可以为他们做的事情,而不是相反。

你似乎在寻找的一般类型的指令被称为内存屏障。事实上,x86有几个来自这个系列的“现代”指令(MFENCE、LFENCE、SFENCE)。它们分别是全Geofence、负载Geofence和存储Geofence。然而,它们在指令集中的重要性仅限于SSE,因为英特尔保证对指令集传统部分的写入进行序列化,这几乎就是为什么这种陈旧的架构很容易成为多线程编程的目标。

有关更多信息,请参阅此答案。