自旋锁
自旋锁最多只能被一个可执行线程持有,如果一个执行线程试图获得一个已经被持有的自旋锁,那么该线程就会一直进行循环—旋转—等待锁重新可用。一个被争用的自旋锁使得请求它的线程在等待锁重新可用时自旋,这样就特别浪费处理器时间,所以自旋锁不应该被长时间持有,相比于互斥锁,互斥锁会让线程阻塞,被阻塞的线程需要换入换出,这样进行上下文切换也会带来一定的开销,因此互斥锁一般适用于持锁时间更长的情况。而自旋锁的持有时间应该尽可能短,最好短于两次线程上下文切换的时间。
读写锁
读共享,写独占,写优先。
如果有写锁请求在等待,则新的读锁请求也应该等待,否则程序可能永远也没有机会获得写锁
一旦写锁被释放,所有在等待的读锁和写锁请求应该公平竞争,而不管请求的先后,只要之前已经在等待就应该有获得锁的机会。
信号量
linux中信号量是一种睡眠锁。如果有一个任务试图获得一个不可用(已经被占用)的信号量时,信号量会将其推进一个等待队列,然后让其睡眠,这时处理器就能去执行其它代码,当持有的信号量可用(被释放)后,处于等待队列中的那个任务将被唤醒,并获得该信号量。
由于争用信号量的进程在等待锁重新变为可用时会睡眠,还要维护等待队列以及唤醒进程,因此开销较大,适用于锁会被长时间持有的情况。信号量的一个有用特性是它可以同时允许任意数量的锁持有者。信号量同时允许的持有者数量可以在声明信号量的时候指定,当持有者数量指定为1的时候,同一时刻只能有一个任务持有,这时可称它为互斥信号量。当持有者数量指定值大于1时称作计数信号量。信号量通过原子操作down(),up()来增减。
互斥锁
互斥锁和互斥信号量很相似,但是它更简洁更高效,因此一般情况下优先使用互斥锁。