什么时候pthread_spin_lock是正确的使用方法(例如通过pthread互斥锁)?

什么时候pthread_spin_lock是正确的使用方法(例如通过pthread互斥锁)?,c,pthreads,C,Pthreads,鉴于pthread_spin_lock可用,我什么时候可以使用它,什么时候不应该使用它们 i、 e.我如何决定使用pthread互斥锁或pthread自旋锁来保护某些共享数据结构?自旋锁是一个“忙等待”锁。它的主要优点是它使线程保持活动状态,并且不会导致上下文切换,因此,如果您知道您将只等待很短的时间(因为您的关键操作非常快),那么这可能会比互斥对象提供更好的性能。相反,如果关键部分需要很长时间,并且需要上下文切换,则互斥将导致对系统的需求减少 TL;DR:视情况而定。简单的回答是,如果您计划在

鉴于pthread_spin_lock可用,我什么时候可以使用它,什么时候不应该使用它们

i、 e.我如何决定使用pthread互斥锁或pthread自旋锁来保护某些共享数据结构?

自旋锁是一个“忙等待”锁。它的主要优点是它使线程保持活动状态,并且不会导致上下文切换,因此,如果您知道您将只等待很短的时间(因为您的关键操作非常快),那么这可能会比互斥对象提供更好的性能。相反,如果关键部分需要很长时间,并且需要上下文切换,则互斥将导致对系统的需求减少


TL;DR:视情况而定。

简单的回答是,如果您计划在极短的时间间隔内保持锁(例如,除了增加计数器之外什么都不做),则自旋锁可能会更好,争用情况预计会很少,但该操作的发生频率足以成为潜在的性能瓶颈。与互斥锁相比,自旋锁的优点是:

  • 解锁时,不需要检查其他线程是否正在等待锁定并唤醒它们。解锁仅仅是一条原子写入指令
  • 未能立即获得锁不会使线程处于睡眠状态,因此,一旦锁可用,它可能能够以更低的延迟获得锁
  • 进入内核空间睡眠或唤醒其他线程不会造成缓存污染
  • 点1将始终成立,但如果您认为好的互斥实现可能会在请求内核帮助等待之前旋转2次,那么点2和点就有点减少。 现在,答案很长:

    在使用自旋锁之前,您需要问问自己,这些潜在的优点是否超过了一个罕见但非常实际的缺点:当持有锁的线程在释放锁之前被调度程序中断时会发生什么。这当然很少见,但即使只是为单个变量增量操作或其他同样微不足道的操作持有锁,也可能发生这种情况。在这种情况下,任何试图获得锁的其他线程都将继续旋转,直到持有锁的线程被调度并有机会释放锁为止如果试图获取锁的线程的优先级高于持有锁的线程,则这可能永远不会发生。这可能是一种极端情况,但即使没有不同的优先级,在锁所有者再次调度之前可能会有很长的延迟,最糟糕的是,一旦这种情况开始,它可能会迅速升级,因为许多线程都希望获得锁,开始在锁上旋转,占用更多的处理器时间,并进一步延迟可能释放锁的线程的调度


    因此,我会小心旋转锁…:-)

    自旋锁只对MP上下文感兴趣。它用于执行伪原子任务。在单处理器系统中,原理如下:

  • 锁定调度程序(如果任务处理中断,则锁定中断)
  • 做我的原子弹大头钉
  • 解锁调度程序
  • 但在MP系统中,我们无法保证其他内核不会执行可能进入我们代码部分的其他线程。为了防止这种情况,已经创建了自旋锁,其目的是推迟其他内核的执行,以防止并发问题。关键部分变成:

  • 锁定调度程序
  • 旋转锁(防止其他芯进入)
  • 我的任务
  • 旋转解锁
  • 任务解锁

  • 如果在调度过程中省略了任务锁,则另一个线程可以尝试进入将在100%CPU上循环的部分,等待下一次调度。如果此任务是高优先级任务,则会产生死锁。

    提高性能的最安全方法是两者的混合:自适应互斥

    当您的系统有多个内核时,您需要旋转数千个周期来捕获低争用或无争用的最佳情况,然后延迟到完全互斥,以便让其他线程获得长争用锁

    POSIX(
    PTHREAD\u MUTEX\u ADAPTIVE\u NP
    )和Win32(
    SetCriticalSectionSpinCount
    )都有自适应互斥,许多平台没有POSIX自旋锁API