在上一篇文章利用汇编语言实现了一个简单的互斥锁。但是它与 mutex 互斥量有着本质的不同:
- 如果一个线程企图获取已加锁状态的互斥量,会立即进入阻塞,即主动让出 cpu.
- 我们自己实现的互斥锁,如果企图获取已加锁状态的 lock 变量,会进入忙等状态而不会让出 cpu.
1. pthread 自旋锁
实际上,pthread 中提供的自旋锁的原理,也就相当于上一篇实验中实现的锁。
注意:pthread 中的自旋锁(pthread_spinlock)不同于内核中的自旋锁(spin_lock)。
所以,自旋锁与互斥量最不同的一个重要特性:它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等,即不停在消耗,执行循环。
2. 自旋锁的数据类型和相关函数
pthread 提供的自旋锁的数据类型是 pthread_spinlock_t.
- 初始化和销毁
- 加锁解释函数
3. 适用场景
- 临界区的代码短小,没有任何阻塞类的函数。
- 多核处理器
什么要这样做:
- 对于单核或者多核:如果临界区有阻塞,会导致线程被切换到新线程,如果新线程也尝试获取锁,会一直自旋(忙等),直到时间片耗尽,造成不必要的 CPU 浪费。
- 对于多核没有阻塞的情况:一次只能运行一个线程,其中一个 CPU 上的线程进入临界区,另一个 CPU 上的线程尝试获取锁会自旋,因为它不会阻塞,所以只要稍稍等一下下就能进入临界区,对于多核 CPU 来说,会提高并发率。对于单核 CPU 来说,通常没有什么问题,如果临界区有阻塞或者时间片耗尽产生调度就会浪费 CPU。
4. 总结
- 理解自旋锁的运行原理
- 理解 pthread 自旋锁的适用场景
- 知乎有关于自旋锁的性能测试和解释,传送门。
练习:用 pthread_spinlock_t 修改上一篇文章中的实验。