http://blog.csdn.net/kyokowl/article/details/6294341html
POSIX threads(简称Pthreads)是在多核平台上进行并行编程的一套经常使用的API。线程同步(Thread Synchronization)是并行编程中很是重要的通信手段,其中最典型的应用就是用Pthreads提供的锁机制(lock)来对多个线程之间共 享的临界区(Critical Section)进行保护(另外一种经常使用的同步机制是barrier)。
Pthreads提供了多种锁机制:
(1) Mutex(互斥量):pthread_mutex_***
(2) Spin lock(自旋锁):pthread_spin_***
(3) Condition Variable(条件变量):pthread_con_***
(4) Read/Write lock(读写锁):pthread_rwlock_***
Pthreads提供的Mutex锁操做相关的API主要有:
pthread_mutex_lock (pthread_mutex_t *mutex);
pthread_mutex_trylock (pthread_mutex_t *mutex);
pthread_mutex_unlock (pthread_mutex_t *mutex);
Pthreads提供的与Spin Lock锁操做相关的API主要有:
pthread_spin_lock (pthread_spinlock_t *lock);
pthread_spin_trylock (pthread_spinlock_t *lock);
pthread_spin_unlock (pthread_spinlock_t *lock);
从 实现原理上来说,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上进行忙等待并不停的进行锁请求,直到获得这个锁为止。linux
因此,自旋锁通常用用多核的服务器。 编程
自旋锁(Spin lock)服务器
自旋锁与互斥锁有点相似,只是自旋锁不会引发调用者睡眠,若是自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是 否该自旋锁的保持者已经释放了锁,"自旋"一词就是所以而得名。其做用是为了解决某项资源的互斥使用。由于自旋锁不会引发调用者睡眠,因此自旋锁的效率远 高于互斥锁。虽然它的效率比互斥锁高,可是它也有些不足之处:
一、自旋锁一直占用CPU,他在未得到锁的状况下,一直运行--自旋,因此占用着CPU,若是不能在很短的时 间内得到锁,这无疑会使CPU效率下降。
二、在用自旋锁时有可能形成死锁,当递归调用时有可能形成死锁,调用有些其余函数也可能形成死锁,如 copy_to_user()、copy_from_user()、kmalloc()等。
所以咱们要慎重使用自旋锁,自旋锁只有在内核可抢占式或SMP的状况下才真正须要,在单CPU且不可抢占式的内核下,自旋锁的操做为空操做。自旋锁适用于锁使用者保持锁时间比较短的状况下。
自旋锁的用法以下:
首先定义:spinlock_t x;
而后初始化:spin_lock_init(spinlock_t *x); //自旋锁在真正使用前必须先初始化
在2.6.11内核中将定义和初始化合并为一个宏:DEFINE_SPINLOCK(x)
得到自旋锁:spin_lock(x); //只有在得到锁的状况下才返回,不然一直“自旋”
spin_trylock(x); //如当即得到锁则返回真,不然当即返回假
释放锁:spin_unlock(x);
结合以上有如下代码段:
spinlock_t lock; //定义一个自旋锁
spin_lock_init(&lock);
spin_lock(&lock);
....... //临界区
spin_unlock(&lock); //释放锁
还有一些其余用法:
spin_is_locked(x)
// 该宏用于判断自旋锁x是否已经被某执行单元保持(即被锁),若是是, 返回真,不然返回假。
spin_unlock_wait(x)
// 该宏用于等待自旋锁x变得没有被任何执行单元保持,若是没有任何执行单元保持该自旋锁,该宏当即返回,否
//将循环 在那里,直到该自旋锁被保持者释放。
spin_lock_irqsave(lock, flags)
// 该宏得到自旋锁的同时把标志寄存器的值保存到变量flags中并失效本地中//断。至关于:spin_lock()+local_irq_save()
spin_unlock_irqrestore(lock, flags)
// 该宏释放自旋锁lock的同时,也恢复标志寄存器的值为变量flags保存的//值。它与spin_lock_irqsave配对使用。
//至关于:spin_unlock()+local_irq_restore()
spin_lock_irq(lock)
//该宏相似于spin_lock_irqsave,只是该宏不保存标志寄存器的值。至关 //于:spin_lock()+local_irq_disable()
spin_unlock_irq(lock)
//该宏释放自旋锁lock的同时,也使能本地中断。它与spin_lock_irq配对应用。至关于: spin_unlock()+local_irq+enable()
spin_lock_bh(lock)
// 该宏在获得自旋锁的同时失效本地软中断。至关于: //spin_lock()+local_bh_disable()
spin_unlock_bh(lock)
//该宏释放自旋锁lock的同时,也使能本地的软中断。它与spin_lock_bh配对//使用。至关于:spin_unlock()+local_bh_enable()
spin_trylock_irqsave(lock, flags)
//该宏若是得到自旋锁lock,它也将保存标志寄存器的值到变量flags中,而且失//效本地中断,若是没有得到锁,它什么也不作。所以若是可以当即 得到锁,它等//同于spin_lock_irqsave,若是不能得到锁,它等同于spin_trylock。若是该宏//得到自旋锁lock,那须要 使用spin_unlock_irqrestore来释放。
spin_trylock_irq(lock)
//该宏相似于spin_trylock_irqsave,只是该宏不保存标志寄存器。若是该宏得到自旋锁lock,须要使用spin_unlock_irq来释放。
spin_trylock_bh(lock)
// 该宏若是得到了自旋锁,它也将失效本地软中断。若是得不到锁,它什么//也不作。所以,若是获得了锁,它等同于spin_lock_bh,若是得 不到锁,它等同//于spin_trylock。若是该宏获得了自旋锁,须要使用spin_unlock_bh来释放。
spin_can_lock(lock)
// 该宏用于判断自旋锁lock是否可以被锁,它实际是spin_is_locked取反。//若是lock没有被锁,它返回真,不然,返回 假。该宏在2.6.11中第一次被定义,在//先前的内核中并无该宏。app
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////less
两种锁的加锁原理ide
互斥锁:线程会从sleep(加锁)——>running(解锁),过程当中有上下文的切换,cpu的抢占,信号的发送等开销。函数
自旋锁:线程一直是running(加锁——>解锁),死循环检测锁的标志位,机制不复杂。post
两种锁的区别url
互斥锁的起始原始开销要高于自旋锁,可是基本是一劳永逸,临界区持锁时间的大小并不会对互斥锁的开销形成影响,而自旋锁是死循环检测,加锁全程消耗cpu,起始开销虽然低于互斥锁,可是随着持锁时间,加锁的开销是线性增加。
两种锁的应用
互斥锁用于临界区持锁时间比较长的操做,好比下面这些状况均可以考虑
1 临界区有IO操做
2 临界区代码复杂或者循环量大
3 临界区竞争很是激烈
4 单核处理器
至于自旋锁就主要用在临界区持锁时间很是短且CPU资源不紧张的状况下。
自旋-互斥锁
下面的英文介绍了混合互斥锁和混合自旋锁,可是不论是第一段说的先上非阻塞锁后上阻塞锁,仍是第二段说的先自旋上锁后进行休眠,反正思路都是先自旋上锁必定时间后在上互斥锁,这种自旋-互斥锁适合各线程持锁时间间隔跨度比较大的状况。
A hybrid mutex behaves like a spinlock at first on a multi-core system. If a thread cannot lock the mutex, it won't be put to sleep immediately, since the mutex might get unlocked pretty soon, so instead the mutex will first behave exactly like a spinlock. Only if the lock has still not been obtained after a certain amount of time (or retries or any other measuring factor), the thread is really put to sleep. If the same system runs on a system with only a single core, the mutex will not spinlock, though, as, see above, that would not be beneficial.
A hybrid spinlock behaves like a normal spinlock at first, but to avoid wasting too much CPU time, it may have a back-off strategy. It will usually not put the thread to sleep (since you don't want that to happen when using a spinlock), but it may decide to stop the thread (either immediately or after a certain amount of time) and allow another thread to run, thus increasing chances that the spinlock is unlocked (a pure thread switch is usually less expensive than one that involves putting a thread to sleep and waking it up again later on, though not by far).