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上进行忙等候并不断的进行锁恳求,直到得到这个锁停止。
所以,自旋锁一般用用多核的服务器。
自旋锁(Spin lock)
自旋锁与互斥锁有点相似,仅仅自旋锁不会引起调用者睡觉,假如自旋锁现已被其他履行单元坚持,调用者就一向循环在那里看是 否该自旋锁的坚持者现已开释了锁,”自旋”一词便是因而而得名。其效果是为了处理某项资源的互斥运用。由于自旋锁不会引起调用者睡觉,所以自旋锁的功率远 高于互斥锁。尽管它的功率比互斥锁高,可是它也有些不足之处:
1、自旋锁一向占用CPU,他在未取得锁的情况下,一向运转--自旋,所以占用着CPU,假如不能在很短的时 间内取得锁,这无疑会使CPU功率下降。
2、在用自旋锁时有或许形成死锁,当递归调用时有或许形成死锁,调用有些其他函数也或许形成死锁,如 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中第一次被界说,在//从前的内核中并没有该宏。