自旋锁:
自旋锁类似于互斥锁,它的性能比互斥锁更高。
自旋锁与互斥锁很重要的一个区别在于:线程在申请自旋锁的时候,线程不会被挂起,它处于等待的状态。
从 实现原理上来讲,Mutex属于sleep-waiting类型的锁。例如在一个双核的机器上有两个线程(线程A和线程B),它们分别运行在Core0和 Core1上。假设线程A想要通过pthread_mutex_lock操作去得到一个临界区的锁,而此时这个锁正被线程B所持有,那么线程A就会被阻塞 (blocking),Core0 会在此时进行上下文切换(Context Switch)将线程A置于等待队列中,此时Core0就可以运行其他的任务(例如另一个线程C)而不必进行忙等待。而Spin lock则不然,它属于busy-waiting类型的锁,如果线程A是使用pthread_spin_lock操作去请求锁,那么线程A就会一直在 Core0上进行忙等待并不停的进行锁请求,直到得到这个锁为止。
所以,自旋锁一般用用多核的服务器。
自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是 否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。其作用是为了解决某项资源的互斥使用。因为自旋锁不会引起调用者睡眠,所以自旋锁的效率远 高于互斥锁。虽然它的效率比互斥锁高,但是它也有些不足之处:
1、自旋锁一直占用CPU,他在未获得锁的情况下,一直运行--自旋,所以占用着CPU,如果不能在很短的时 间内获得锁,这无疑会使CPU效率降低。
2、在用自旋锁时有可能造成死锁,当递归调用时有可能造成死锁,调用有些其他函数也可能造成死锁,如 copy_to_user()、copy_from_user()、kmalloc()等。
因此我们要慎重使用自旋锁,自旋锁只有在内核可抢占式或SMP的情况下才真正需要,在单CPU且不可抢占式的内核下,自旋锁的操作为空操作。自旋锁适用于锁使用者保持锁时间比较短的情况下。
读写锁: 读写锁用于读称为共享锁,读写锁用于写称为排他锁;
只要没有线程持有给定的读写锁用于写,那么任意数目的线程可以持有读写锁用于读;
仅当没有线程持有某个给定的读写锁用于读或者写的时候,才能分配读写锁用于写;
读写锁有三种状态:读加锁状态、写加锁状态和不加锁状态
一次只有一个线程可以占有写模式的读写锁,但是多个线程可以同时占有读模式的读写锁。(这也是它能够实现高并发的一种手段)
当读写锁在写加锁模式下,任何试图对这个锁进行加锁的线程都会被阻塞,直到写进程对其解锁。
当读写锁在读加锁模式下,任何线程都可以对其进行读加锁操作,但是所有试图进行写加锁操作的线程都会被阻塞,直到所有的读线程都解锁。
所以读写锁非常适合对数据结构读的次数远远大于写的情况。
如果严格按照上述读写锁的操作进行的话,那么当读者源源不断到来的时候,写者总是得不到读写锁,就会造成不公平的状态。
一种避免这种不公平状态的方法是:
当处于读模式的读写锁接收到一个试图对其进行写模式加锁操作时,便会阻塞后面对其进行读模式加锁操作的线程。
这样等到已经加读模式的锁解锁后,写进程能够访问此锁保护的资源。