- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
根据这个问题here使用 pthread_spin_lock
锁定关键部分是危险的,因为线程可能会被调度程序中断,而其他线程可能会在该资源上保持旋转状态。
假设我决定从 pthread_spin_lock
切换到通过 atomic built-in + compare_and_swap idion 实现的锁:这件事会改善还是我仍然会遇到这个问题?
自从使用 pthread
后,禁用抢占似乎没什么用,如果我使用通过原子实现的锁或任何我可以查看的东西,我能做些什么吗?
我对锁定一个小的关键区域很感兴趣。
最佳答案
pthread_mutex_lock
通常有一个快速路径,它使用原子操作来尝试获取锁。如果没有锁,这会非常快。只有当锁已经持有时,线程才会通过系统调用进入内核。内核获取一个自旋锁,然后重新尝试获取互斥锁,以防它在第一次尝试后被释放。如果此尝试失败,则将调用线程添加到与互斥锁关联的等待队列,并执行上下文切换。内核还在互斥量中设置一个位来指示有一个等待线程。
pthread_mutex_unlock
也有一个快速路径。如果等待线程标志被清除,它可以简单地释放锁。如果设置了标志,则线程必须通过系统调用进入内核,以便唤醒等待的线程。同样,内核必须获得一个自旋锁,以便它可以操纵其线程控制数据结构。如果最终没有线程等待,内核可以释放锁。如果有线程在等待,它会变为可运行状态,互斥体的所有权会在不释放的情况下转移。
这个小舞蹈中有许多微妙的竞争条件,希望一切正常。
由于尝试获取锁定互斥锁的线程被上下文切换,它不会阻止拥有互斥锁的线程运行,这使所有者有机会退出其关键部分并释放互斥锁。
相比之下,尝试获取锁定的自旋锁的线程只会自旋,从而消耗 CPU 周期。这有可能阻止拥有自旋锁的线程退出其临界区并释放锁。旋转线程可以在其时间片被消耗时被抢占,从而允许拥有锁的线程最终重新获得控制权。当然,这对性能来说不是很好。
在实践中,自旋锁用于当线程拥有锁时不可能被抢占的地方。内核可以设置一个 per-cpu 标志以防止它从中断服务例程执行上下文切换(或者它可以提高中断优先级以防止可能导致上下文切换的中断,或者它可以完全禁用中断)。用户线程可以通过提高其优先级来防止自己被(同一进程中的其他线程)抢占。请注意,在单处理器系统中,防止当前线程被抢占就不需要自旋锁。或者,在多处理器系统中,您可以将线程绑定(bind)到 cpus(cpu 亲和性),这样它们就不能相互抢占。
所有的锁最终都需要一个原子原语(好吧,高效的锁;参见 here 的反例)。如果互斥量竞争激烈,互斥量可能效率低下,导致线程不断进入内核并进行上下文切换;特别是如果临界区小于内核开销。自旋锁可以更有效,但前提是所有者不能被抢占并且关键部分很短。请注意,当线程尝试获取锁定的互斥量时,内核仍必须获取自旋锁。
就个人而言,我会使用原子操作来处理共享计数器更新之类的事情,而使用互斥锁来处理更复杂的操作。只有在分析之后,我才会考虑用自旋锁替换互斥锁(并弄清楚如何处理抢占)。请注意,如果您打算使用条件变量,则别无选择,只能使用互斥量。
关于c - 抢占、pthread_spin_lock 和原子内置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22385788/
根据这个问题here使用 pthread_spin_lock 锁定关键部分是危险的,因为线程可能会被调度程序中断,而其他线程可能会在该资源上保持旋转状态。 假设我决定从 pthread_spin_lo
鉴于 pthread_spin_lock 可用,我什么时候使用它,什么时候不应该使用它们? 即我将如何决定使用 pthread 互斥锁或 pthread 自旋锁来保护某些共享数据结构? 最佳答案 简短
我的 C++ 多线程应用程序在 valgrind 3.8.0 及最新版本的 pthread_spin_lock 中挂起。但它不会在 3.6.0、3.6.1 和 3.7.0 中发生。有人知道这个的任何解
我是一名优秀的程序员,十分优秀!