什么时候pthread_spin_lock正确使用(例如pthread互斥锁)?

时间:2011-07-06 21:43:18

标签: c pthreads

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

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

4 个答案:

答案 0 :(得分:44)

简短的回答是,当您计划在极短的时间间隔内保持锁定时,螺旋锁可以更好(例如,除了增加计数器之外什么都不做),并且预计争用很少,但操作正在发生通常足以成为潜在的性能瓶颈。螺旋锁相对于互斥锁的优点是:

  1. 解锁时,无需检查其他线程是否正在等待锁定并将其唤醒。解锁只是一个单独的原子写指令。
  2. 无法立即获取锁定不会使您的线程进入休眠状态,因此一旦可用,它就可以以更低的延迟获得锁定。
  3. 进入内核空间睡眠或唤醒其他线程不存在缓存污染的风险。
  4. 第1点将始终有效,但如果您认为好的互斥实现可能会在请求内核等待帮助之前旋转相当多次,则第2点和第3点的实用性会有所降低。

    现在,答案很长:

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

    因此,我会小心使用自旋锁......: - )

答案 1 :(得分:14)

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

TL; DR:这取决于。

答案 2 :(得分:7)

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

当你的系统有多个内核时,你会旋转几千个周期来捕获低或无争用的最佳情况,然后推迟到完全互斥锁以获得长期争用锁的其他线程。

POSIX(PTHREAD_MUTEX_ADAPTIVE_NP)和Win32(SetCriticalSectionSpinCount)都有自适应互斥锁,许多平台都没有POSIX自旋锁API。

答案 3 :(得分:1)

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

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

    1. 锁定调度程序
    2. SpinLock(防止进入其他核心)
    3. 我的任务
    4. SpinUnlock
    5. 任务解锁
    6. 如果省略任务锁定,则在调度期间,另一个线程可能会尝试输入一个将在100%CPU等待下一个调度的情况下循环的部分。如果此任务是高优先级的任务,则会产生死锁。