目录
理解原子指令
自旋锁原理
校园卡举例:
老师的卡方是更高权限的红卡放在桌子上,代表锁。学生的卡是更低权限的绿卡,两位学生想要进入临界区的条件是获得这把锁;所以他们需要抢着把自己手里的卡和老师手里的卡进行交换(这个交换操作是原子的!!)
当某学生 抢到了红卡时,该学生就得到了锁,并把自己的绿卡换回到桌上,而其他学生得不到红卡,就不停把手里的卡与桌上的卡进行交换;当某学生执行完临界区代码时,该学生把红卡换回桌上,归还锁,这样其他人可以获得这把锁
所以说,只要那个得到锁的学生没从临界区出来也就是没把红卡换回到桌上,其他人就得不到红色卡,他们就一直在交换交换交换——无效交换;
Q1:如果某线程lock成功获得了锁,但在unlock之前,线程crash或者return,会发生什么?
发生死锁。因为此时红色卡在这个线程手上,并永远的消失了。也就是锁永远被锁住打不开了。
老师的小点子:制作一个类,用构造和析构实现lock和unlock,这样就可以避免忘记unlock了,因为函数退出之前会自动调用其析构函数
Q2:为什么用 xchg(&table, YES)
因为我们需要 保证lock和unlock在任何情况下都“正确执行”,所以需要使用原子指令
自旋锁汇总: 下述代码为教科书上常见代码,与上面代码等效的
在操作系统上实现互斥
引入
自旋锁的缺陷:如果线程数比cpu多会发生什么?
持有自旋锁的线程可能会被操作系统切换出去!!图示如下
根据下图可以看到,随着线程数增加1-16,效率明显减小,存在两个瓶颈,锁获取和sum的交换
其实在实际应用中,当越来越多的人争抢这把锁时,效率会急速下降,如下图所示
自旋锁唯一使用场景
操作系统内核的并发数据结构,而且是短临界区
实现线程 + 长临界区的互斥
Q4: 是否可以该线程抢不到自旋锁的时候,把正在执行该线程的cpu让渡给其他线程?
- 操作系统的mutex_lock()就是这样哒,但是需要进入操作系统内核syscall
总结,两种锁
那么如何选择两种锁呢?这里没懂