递归锁:在同一个线程可以多次获取同一个锁,不会产生死锁;
非递归锁:在同一个线程中,加锁后不可以再次获取该锁,如果获取可能产生死锁;
Linux的互斥量pthread_mutex_t是非递归锁,但是可以在创建互斥量时设置PTHREAD_MUTEX_RECURSIVE属性,将pthread_mutex_t设置为递归锁。
读写锁有三种状态:读模式下加锁、写模式下加锁、不加锁。写模式下的读写锁一次只有一个线程可以占有,读模式下的读写锁多个线程可以同时占有。
写加锁状态时,所有试图加锁的线程都会被阻塞。
读加锁状态时,所有试图在读模式下加锁的线程都可以得到访问权,但是希望在写模式下加锁的线程会被阻塞,直到所有读锁释放
为了避免写模式锁请求一直不能满足,大多数操作系统会阻塞随后的读模式加锁请求。
互斥锁和读写锁对比:
互斥锁只有锁住和不加锁的状态,而且一次只有一个线程可以加锁
读写锁和互斥锁有些类似,但是并行性更高,有三种状态如上。
读写锁适合的场景就是对临界资源读的次数远大于写的次数的情况。
自旋锁就是某个线程想要进入临界区时,如果临界区已经被加锁,那么自旋锁并不会阻塞线程,而是轮询检测自旋锁的状态,也就是自旋。本质上是为了减少线程阻塞挂起再唤醒产生的消耗。在自旋期间,CPU不能做其他事,所以自旋锁适合临界区的代码非常短的场景,开销会非常小。内核的一些数据结构中自旋锁被广泛的使用。
互斥锁和自旋锁对比:
实际中很多互斥量的实现其实非常高效,比如有些互斥量在申请锁的时候会自旋一段时间,自旋时间超过某个阈值才会休眠。在之前使用自旋锁的地方使用这些高效的互斥量性能也不差。还有由于现代处理器的进步,上下文切换也越来越快。