preemption,pthread_spin_lock和atomic built-in

Abr*_*ile 2 c linux multithreading pthreads atomic

根据这个问题,这里使用pthread_spin_lock是危险的,以锁定一个关键部分,因为线程可能会被调度程序中断,并且该资源上的其他线程可能会停止旋转.

假设我决定切换 pthread_spin_lock到通过原子内置+ compare_and_swap idion实现的锁:这个东西会改善还是我会遇到这个问题?

因为pthread它似乎没有什么可以禁用抢占,有什么我可以做的,以防我使用通过原子实现的锁或任何我可以看看的?

我有兴趣锁定一个小的关键区域.

pat*_*pat 6

pthread_mutex_lock通常有一个快速路径,它使用原子操作来尝试获取锁.如果锁不是拥有的,这可能非常快.只有当锁已被保持时,线程才会通过系统调用进入内核.内核获取自旋锁,然后重新尝试获取互斥锁,以防自第一次尝试以来它被释放.如果此尝试失败,则将调用线程添加到与互斥锁关联的等待队列,并执行上下文切换.内核还在互斥锁中设置一个位以指示存在等待线程.

pthread_mutex_unlock也有一条快速的道路.如果等待的线程标志清除,它可以简单地释放锁定.如果设置了该标志,则线程必须通过系统调用进入内核,以便可以唤醒等待的线程.同样,内核必须获取自旋锁,以便它可以操纵其线程控制数据结构.如果没有线程等待,内核就可以释放锁.如果有一个线程正在等待,它将成为可运行的,并且互斥锁的所有权在没有被释放的情况下被转移.

在这个小小的舞蹈中有许多微妙的竞争条件,希望这一切都能正常运作.

由于尝试获取锁定互斥锁的线程是上下文切换出来的,因此它不会阻止线程拥有互斥锁运行,从而使所有者有机会退出其临界区并释放互斥锁.

相反,尝试获取锁定自旋锁的线程只是旋转,消耗CPU周期.这有可能阻止拥有自旋锁的线程退出其关键部分并释放锁定.旋转线程可以在其时间片被消耗时被抢占,从而允许拥有该锁的线程最终重新获得控制权.当然,这对性能来说并不好.

实际上,在拥有锁的情况下线程不可能被抢占的情况下使用自旋锁.内核可以设置per-cpu标志以防止它从中断服务例程执行上下文切换(或者它可以提高中断优先级以防止可能导致上下文切换的中断,或者它可以完全禁用中断).用户线程可以通过提高其优先级来防止自身被抢占(通过同一进程中的其他线程).请注意,在单处理器系统中,防止当前线程被抢占消除了对自旋锁的需要.或者,在多处理器系统中,您可以将线程绑定到cpus(cpu affinity),以便它们不会相互抢占.

所有锁最终都需要一个原子基元(好的,有效的锁; 有关反例,请参见此处).如果它们具有高度竞争性,则互斥量可能效率低下,导致线程不断进入内核并进行上下文切换; 特别是如果临界区小于内核开销.旋转锁可以更有效,但仅当主人不能被抢占且关键部分很短时.请注意,当线程尝试获取锁定的互斥锁时,内核仍必须获取自旋锁.

就个人而言,我会将原子操作用于共享计数器更新,以及用于更复杂操作的互斥锁.只有在进行性能分析后,我才会考虑用自旋锁替换互斥锁(并弄清楚如何处理抢占).请注意,如果您打算使用condvars,则别无选择,只能使用互斥锁.