Synchronization 如果不同处理器中的两个进程试图同时获取锁,会发生什么情况

Synchronization 如果不同处理器中的两个进程试图同时获取锁,会发生什么情况,synchronization,locking,smp,multiprocessor,Synchronization,Locking,Smp,Multiprocessor,好的,我正在阅读关于同步的内容,我阅读了各种算法,比如自旋锁、信号量和互斥,以避免竞争条件 然而,当多个进程同时访问数据时,这些算法不能防止SMP中的竞争条件 例如,假设处理器A中的线程1运行 锁(mutex1); 撤回(1000); 解锁(mutex1) 处理器B中的线程2运行 锁(mutex1); 押金(1000); 押金(1000); 解锁(mutex1) 当两个线程同时运行时,两个线程将同时处于临界段 唯一的解决方案(应该是硬件级别的)是使每个处理器彼此稍微分离,但这会破坏并行性的目的

好的,我正在阅读关于同步的内容,我阅读了各种算法,比如自旋锁、信号量和互斥,以避免竞争条件

然而,当多个进程同时访问数据时,这些算法不能防止SMP中的竞争条件

例如,假设处理器A中的线程1运行 锁(mutex1); 撤回(1000); 解锁(mutex1)

处理器B中的线程2运行 锁(mutex1); 押金(1000); 押金(1000); 解锁(mutex1)

当两个线程同时运行时,两个线程将同时处于临界段

唯一的解决方案(应该是硬件级别的)是使每个处理器彼此稍微分离,但这会破坏并行性的目的

是否有任何硬件级别的支持来避免多个处理器试图同时获取锁的情况


(这不是原子性的问题,而是精确并行性的问题,我想知道SMP是如何处理它的)。

您可能想看看内存障碍

在这种情况下,锁将使用内存屏障,因此多个处理器无法同时访问锁中使用的内部值

一些体系结构还允许锁定除1之外的所有核心,以实现这一点。例如,x86使用一个锁前缀,当添加到指令时,该前缀将在该指令期间锁定对内存的访问。(例如:LOCK ADD EAX,1表示寄存器的原子增量)

不支持锁或原子指令的体系结构使用比较和交换或测试和设置/交换。通常它涉及一个小的指令循环,在高级中可能看起来像

while (target != value) target = value;

这看起来可能不会执行多次,但它可以确保在两条指令之间的值不会从其下面更改。这种方法的缺点是,如果目标上存在高争用,那么它可能会消耗比您希望的更多的时钟周期,但它往往发生得足够快,因此永远不会真正引起注意。

这是一个典型的死锁问题。我不确定硬件支持(但我几乎可以肯定这在硬件级别是受支持的),但是,我可以给您一个关于数据库死锁问题解决方案的示例。如果您知道所有依赖项,您就知道应该“终止”哪个依赖项,这样,给定节点的命令将失败,但系统将打破死锁,其他节点不会失败。我认为在硬件层面也应该采用同样的方法。

我强烈推荐。不同的硬件体系结构为同步数据访问提供了不同的低级工具,包括一些几乎没有帮助的体系结构。Schimmel的书提供了甚至可以在这些架构上工作的算法


我希望我能很容易地找到我的副本来总结内容。

互斥锁的全部要点是,即使两个内核试图同时获取互斥锁,其中一个将被阻止,直到另一个释放它。一个允许两个内核同时持有该互斥体的互斥体将被完全破坏,并且对于其唯一的预期用途是无用的

在硬件的某个地方有一个总线仲裁器,它只允许一个内核控制连接这两个内核的总线。如果任何一个核心已经有内存在私有缓存中保存互斥,那么该核心将获胜。否则,谁先得到公共汽车谁就赢

总线仲裁器可以以多种方式工作,但通常会旋转。因此,如果核心是0、1、2和3,并且核心2最后有一条总线,那么总线接下来将转到核心3(如果它想要),否则核心0(如果它想要),否则核心1(如果它想要),否则返回核心2。根据具体涉及的总线(无论是两个核心的二级缓存之间的冲突,还是内存本身的冲突,或者其他什么),一些核心可以作为一个单元与其他核心组竞争,然后再为哪个特定的核心先获得它而竞争

这可能是一个核心已经控制了总线,因此它将彻底获胜。通常,仲裁器允许核心持续保持总线,只要它继续希望将总线用于一些事务,以避免浪费性的切换,从而不允许核心向前推进


具体细节可能会因大量因素而有所不同,包括核心的排列方式、哪些核心在其缓存中的锁处于何种状态、谁最后拥有总线以及总线仲裁器是否使用时间片、循环或其他机制,等等。但是,任何不能保证一个且只有一个内核最终获得锁的实现都将被视为严重破坏。

您可以使用TLS和XCHG等原子指令来防止这种情况

如何确保指令的原子性

您可以在执行指令之前禁用所有中断,然后在指令完成后启用所有中断。这对多核系统没有帮助,因为禁用处理器1中的中断对处理器2没有任何影响。在多核系统上,通过防止其他CPU访问内存总线(内存屏障),确保指令的原子性

因此,如果您使用这些指令实现信号量,那么SMP上就不会有问题

使用TSL实现互斥锁和互斥解锁:

 mutex_lock:
    TSL REGISTER, MUTEX ; copy mutex to register and sets mutex
    CMP REGISTER, #0    ; compare mutex to zero
    JZE ok              ; if zero return
    CALL thread_yield   ; else: mutex is busy, schedule another thread
    JMP mutex_lock      ; try again later
 ok: RET

 mutex_unlock:
    MOVE MUTEX,#0       ; free mutex
    RET
您可以在此处找到有关TSL的一些信息:


一本好书可以帮助您:

这是否意味着SMP中的所有锁定算法都是使用内存屏障实现的(除了原子指令)?从我在内核中所做的工作和在编译器中看到的情况来看,它是这样的。通常在更改这些值时,您必须使其他内核上的缓存无效(这涉及内存屏障)。这是一个比我的解释更不可怕的误导性解释