根据这个问题, 在这里通过使用pthread_spin_lock
是危险的locking关键部分,因为线程可能会被调度程序中断,并且该资源上的其他线程内容可能会被旋转。
假设我决定从pthread_spin_lock
切换到通过primefaces内置+ compare_and_swap idion实现的locking:这个事情会改善还是会受到这个问题的困扰?
因为用pthread
它似乎没有什么禁用抢占,有什么我可以做的情况下,我使用通过primefaces实现的锁或任何我可以看看?
我有兴趣locking一个小的关键区域。
pthread_mutex_lock
通常有一个快速路径,它使用原子操作来获取锁。 如果锁没有,这可以是非常快的。 只有当锁已经被锁定,线程才会通过系统调用进入内核。 内核获取自旋锁,然后重新尝试获取互斥锁,以防自第一次尝试释放互斥锁。 如果此尝试失败,则将调用线程添加到与该互斥锁关联的等待队列中,并执行上下文切换。 内核还在互斥体中设置了一个位,表示有一个等待线程。
pthread_mutex_unlock
也有一个快速路径。 如果等待的线程标志清除,则可以简单地释放该锁。 如果标志被设置,线程必须通过系统调用进入内核,以便等待的线程可以被唤醒。 同样,内核必须获得一个自旋锁,以便它可以操作它的线程控制数据结构。 如果没有线程在等待,锁可以被内核释放。 如果有一个线程正在等待,它就会运行,并且互斥量的所有权被转移而不被释放。
这个小舞蹈有许多微妙的竞赛条件,希望一切正常。
由于尝试获取锁定的互斥锁的线程被切换到上下文环境,因此它不会阻止拥有互斥锁的线程运行,从而使所有者有机会退出其临界区并释放互斥锁。
相反,尝试获取锁定旋转锁的线程只是旋转,消耗CPU周期。 这有可能阻止拥有自旋锁的线程退出其关键部分并释放锁。 旋转的线程在其时间片被消耗时可被抢占,从而允许拥有锁的线程最终重新获得控制权。 当然,这对于性能来说并不好。
在实践中,使用自旋锁的地方是,在拥有锁的情况下线不可能被抢占。 内核可能会设置一个per-cpu标志,以防止它从中断服务程序执行上下文切换(或者可能会提高中断优先级以防止可能导致上下文切换的中断,或者可能完全禁用中断)。 用户线程可以通过提高优先级来防止自己被抢占(由同一进程中的其他线程抢占)。 请注意,在单处理器系统中,防止当前线程被抢占,从而不需要自旋锁定。 或者,在多处理器系统中,可以将线程绑定到cpu(cpu affinity),以便它们不能抢占彼此。
所有的锁最终都需要一个原子基元(很好,高效的锁;参见这里的一个反例)。 如果互斥性很强,互斥锁可能效率低下,导致线程不断进入内核并进行上下文切换; 特别是如果临界区小于内核开销。 旋转锁可以更有效率,但只有当拥有者不能被抢占和关键部分短。 请注意,当线程尝试获取锁定的互斥锁时,内核仍然必须获取旋转锁定。
就个人而言,我会使用原子操作的东西,如共享计数器更新,互斥和更复杂的操作。 只有在分析之后,我才会考虑用自旋锁代替互斥锁(并找出如何处理抢占)。 请注意,如果您打算使用condvars,则别无选择,只能使用互斥锁。