锁
重点1:锁
自旋锁
特点:当线程获取锁失败时,线程会一直处于忙等待状态,直到拿到锁。
使用场景:在非抢占式内核中非常有用。用户层适用于不允许抢占的实时调度中。并且当==被锁住的代码执行时间很短时==。
注:因为在抢占式的内核或实时调度中,当一个线程获取自旋锁失败后会一直处于阻塞状态时,操作系统会将该线程挂起,让别的线程进行工作。
使用方法:
1 |
|
互斥锁
特点:当互斥锁加锁失败后,线程会释放CPU,给其他线程。
使用方法:
1 |
|
缺点:互斥锁加锁失败,会从用户态陷入到内核态,让内核帮我们切换线程,虽然简化了使用锁的难度,但是==存在两次线程上下文切换的成本。==
- 当线程加锁失败时,内核会把线程的状态从**[运行]状态设置为[睡眠状态]**,然后把CPU切换给其他线程运行。
- 接着,当锁被释放时,之前的**[睡眠]状态的线程会变成[就绪]状态**,然后内核会在合适的时间,把CPU切换给该进程运行。

使用场景:==被锁住的代码执行时间很长时==
读写锁🔒
特点:由读锁和写锁两部分构成。如果只读取共享资源用【读锁】加锁,如果要修改共享内存使用【写锁】加锁。
使用场景:适用于能够明确区分读操作和写操作的场景。
工作原理:
- 当写锁没有被线程持有时,多个线程能够并发的持有读锁,这大大的提高了共享资源的访问效率,因此读锁是用于读取共享资源的场景,所以多个线程同时持有读锁也不会破坏共享资源的数据。
- 当写锁被线程持有时,读线程获取读锁的操作会被阻塞,而其他写线程获取写锁的操作也会被阻塞。
实现方式:根据锁的实现方式可以分为读优先锁和写优先锁。
读优先锁:期望读锁能够被更多的线程获取,以便提高线程的并发性。例如,如下线程A获取了读锁,写线程B再获取写锁时,被阻塞,并且在后续的阻塞过程中,后续来的读线程C仍可以成功的获取读锁,最后直到线程A和线程C释放读锁后,写线程B才能获取写锁。 如下图所示:
写优先锁:优先写线程工作,当读进程A获取读锁后,写线程尝试获取写锁失败,处于阻塞。读线程C获取读锁时,==也获取失败,处于阻塞状态==。当读进程A执行完毕,释放读锁后,写线程B获取写锁。

读优先锁的缺点是可能会导致可能会使得写线程处于饥饿状态;而写优先锁的缺点是可能会导致读进程处于饥饿状态。
因此为了解决该问题,引入==【公平读写锁】:用队列把获取锁的线程排队,不管是写线程还是读线程都按照先进先出的原则加锁,这样读线程仍然可以并发,也不会出现饥饿现象。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ò.ó!
评论