【第三章:BAT等名企面试真题解析8讲】第9节:阿里面试真题解析之互斥锁和自旋锁相关问题
前言
在多处理器系统环境中需要保护资源避免由于并发带来的资源访问竞争导致的问题,就需要互斥访问,也就是需要引入锁的机制。只有获取了锁的进程才能访问资源。互斥锁和自旋锁是两种代表性的锁。在实际面试当中对于锁相关的问题出现的频率较高,一般涉及到并发访问,线程安全,线程同步相关问题就会问到互斥锁和自旋锁。本文将先对互斥锁和自旋锁的作用,实现以及使用场景做一个重点分析,然后例举6道我在面试阿里时的真题进行分析。
多线程并发访问问题
当多个线程并发访问共享资源时,有可能产生并发访问的安全性问题,可能会导致共享资源被破坏,导致非预期的结果。比如C++ STL当中的vector,map等等都是非并发安全的容器。如果想要解决并发访问的安全性问题就需要引入线程同步机制。
线程间同步指的是:当有一个线程在对共享资源进行操作时,其他线程都不可以对这个资源进行操作,直到该线程完成操作。简单来说,就是线程之间需要达到协同一致。
一般线程间同步机制有:共享内存,信号量机制,锁机制,信号机制等等。其中对于锁的使用是最普遍的方式。
互斥锁:
互斥锁的作用:
互斥锁是为实现保护共享资源而提出一种锁机制。采用互斥锁保护临界区,防止竞争条件出现。当某个线程无法获取互斥锁时,该线程会被挂起,当其他线程释放互斥锁后,操作系统会唤醒被挂起在这个锁上的线程,让其运行。
互斥锁的实现:
在Linux下互斥锁的实现是通过futex这个基础组件。
互斥锁加锁解锁开销很大,需要从用户态切换到内核态,上下文切换以及涉及缓存的更新等等。通常很多同步操作发生的时候并没有竞争的产生,此时上述开销就没有必要。考虑到这个因素,futex通过用户空间的共享内存以及原子操作,在共享的资源不存在竞争的时候,不会进行系统调用而是只有当竞争出现的情况下再进行系统调用陷入内核。进程或者线程在没有竞争的情况下可以立刻获取锁。具体来说,futex的优化方式如下:
futex将同步过程分为两个部分,一部分由内核完成,一部分由用户态完成;如果同步时没有竞争发生,那么完全在用户态处理;否则,进入内核态进行处理。减少系统调用的次数,来提高系统的性能是一种合理的优化方式。
互斥锁的使用场景:
-
解决线程安全问题,一次只能一个线程访问被保护的资源。
-
被保护资源需要睡眠,那么可以使用互斥锁。
自旋锁:
自旋锁的作用:
自旋锁也是为实现保护共享资源而提出一种锁机制。自旋锁不会引起调用线程阻塞,如果自旋锁已经被别的线程持有,调用线程就一直循环检测是否该自旋锁已经被释放。
自旋锁的特点:
- 线程不会阻塞,不会在内核态和用户态之间进行切换。
- 消耗 CPU: 因为自旋锁会不断的去检测是否可以获得锁,会一直处于这样的循环当中,这个逻辑的处理过程消耗的 CPU相对其实际功能来说是浪费的。
自旋锁的实现:
CAS(compare and swap) 是实现自旋锁的基础。CAS
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
收割BAT:C++校招学习路线总结 文章被收录于专栏
<p> 《收割BAT:C++校招学习路线总结》,专刊共计17节。专刊分为五大主要内容,包括后台开发学习路线、简历制作,面试技巧、BAT等名企面试真题解析和工作学习常用工具。本专刊将介绍我在技术成长过程当中的经验,通关BAT的面试技巧,并结合亲身经历的面试真题由浅入深的讲解后台开发方向的重点问题,让你们的求职之路更加顺畅。 本专刊购买后即可解锁所有章节,故不可以退换哦~ </p> <p> <br /> </p>