POSIX threads (Pthreads)是一组常用的API,用于多核平台上的并行编程。线程同步是并行编程中非常重要的通信手段,最典型的应用是用Pthreads提供的锁机制(另一种常见的同步机制是barrier)来保护多个线程共享的临界段。

Pthreads提供了各种锁机制:(1)互斥:pthread_mutex_***(2)自旋锁:pthread _ spin _ * * * (3)条件变量:pthread _ con _ * * * (4)读取。写锁:pthread _ rwlock _ * * pthread提供的与互斥锁操作相关的API主要有:pthread _ Mutex _ lock(pthread _ Mutex _ t * Mutex);pthread _ mutex _ try lock(pthread _ mutex _ t * mutex);pthread _ mutex _ unlock(pthread _ mutex _ t *互斥);Pthreads提供的与自旋锁操作相关的API主要有:pthread _ Spin _ Lock(pthread _ Spin Lock _ t * Lock);pthread _ spin _ try lock(pthread _ spin lock _ t * lock);pthread _ spin _ unlock(pthread _ spin lock _ t * lock);从实现原理上来说,互斥属于睡眠等待型锁。比如一个双核机器上有两个线程(线程A和线程B),分别运行在Core0和Core1上。假设线程A想通过pthread_mutex_lock操作获得一个临界段的锁,而这个锁此时正被线程B持有,那么线程A就会被阻塞,此时Core0会进行上下文切换将线程A放入等待队列,然后Core0就可以运行其他任务(比如另一个线程C)而不必等待。另一方面,旋转锁是一种忙等待锁。如果线程A使用pthread_spin_lock请求锁,那么线程A将一直忙于等待Core0,并一直发出锁请求,直到它获得锁。

所以自旋锁一般用多核服务器。

旋转锁

自旋锁类似于互斥锁,除了它不会导致调用者睡眠。如果自旋锁已被其他执行单元持有,调用者将继续在那里循环,以查看自旋锁的持有者是否已释放该锁,因此得名' spin '它的功能是解决一个资源的互斥使用。因为自旋锁不会导致调用者睡眠,所以自旋锁的效率比互斥锁高很多。虽然它的效率比互斥锁高,但也有一些缺点1、自旋锁总是占用CPU,在没有获得锁的情况下一直运行——自旋,所以占用CPU。如果短时间内无法获得锁,无疑会降低CPU效率。2、使用自旋锁时可能导致死锁,递归调用时可能导致死锁,调用其他一些函数时可能导致死锁,如copy_to_user()、copy_from_user()、kmalloc()等。因此,我们应该小心使用自旋锁。只有当内核是抢占式或SMP时,才真正需要自旋锁。在单CPU和非抢占式内核下,自旋锁的操作是空的。旋转锁适合锁用户短时间保管锁。自旋锁的用法如下:首先定义:spin lock _ t x;然后初始化:spin _ lock _ init(spin lock _ t * x);//旋转锁必须在实际使用之前初始化。2.6.11内核中定义和初始化合并成一个宏:DEFINE_SPINLOCK(x)获取自旋锁:spin _ lock(x);//只有获得锁才返回,否则一直“自旋”spin _ try lock(x);//如果立即获得锁,则返回true否则会立即返回假释放锁:spin _ unlock(x);综合以上,有以下代码段:spinlock _ t lock//定义一个自旋锁spin _ lock _ init(lock);spin_lock(锁);.//临界区spin _ unlock(lock);//释放锁还有其他用途:spin_is_locked(x) //这个宏用来判断自旋锁x是否已经被一个执行单元持有(即锁定),如果是则返回true,否则返回false。Spin_unlock_wait(x) //这个宏用于等待自旋锁X不再被任何执行单元持有。如果没有执行单元持有自旋锁,宏将立即返回,并且没有//将在那里循环,直到自旋锁被持有者释放。Spin _ lock _ irqsave (lock,flags)//该宏获取自旋锁,并将标志寄存器的值保存在变量flags中,并使本地中断无效。相当于:spin _ lock()local _ IRQ _ save()spin _ unlock _ IRQ restore(lock,flags)//这个宏释放自旋锁,同时将flag寄存器的值恢复为//变量flags保存的值。它与spin_lock_irqsave成对出现。//相当于:spin _ unlock()local _ IRQ _ restore()spin _ lock _ IRQ(lock)//这个宏类似于spin_lock_irqsave,只是不保存标志寄存器的值。相当于//in:spin _ lock()local _ IRQ _ disable()spin _ unlock _ IRQ(lock)//这个宏释放自旋锁,使能本地中断。它与spin_lock_irq成对出现。相当于:spin _ unlock()local _ IRQ enable()spin _ lock _ BH(lock)//这个宏在获取自旋锁时本地软中断失败。相当于://spin _ lock()local _ BH _ disable()spin _ unlock _ BH(lock)//这个宏释放自旋锁,使能本地软中断。它与spin_lock_bh成对//使用。相当于:spin _ unlock()local _ BH _ enable()spin _ trylock _ IRQ save(lock,flags)//如果宏获得了自旋锁,也会将标志寄存器的值保存在变量flags中,在本地中断。如果它没有获得锁,它将什么也不做。因此,如果能立即获得锁,则等于//与spin_lock_irqsave相同,如果不能获得锁,则等于spin_trylock。如果宏//获得了自旋锁,它需要使用spin_unlock_irqrestore来释放它。Spin_trylock_irq(lock) //这个宏类似于spin_trylock_irqsave,只是它不保存标志寄存器。如果宏获得了自旋锁,它需要使用spin_unlock_irq来释放它。Spin_trylock_bh(lock) //如果宏获得自旋锁,也会使本地软中断失败。如果它不能得到锁,它什么也不做。因此,如果获得锁,则相当于spin_lock_bh,如果没有获得锁,则相当于spin_trylock。

如果宏获得了自旋锁,需要使用spin_unlock_bh来释放它。Spin_can_lock(lock) //这个宏用来判断自旋锁是否可以锁定,实际上是spin_is_locked的逆过程。//如果lock没有被锁定,则返回true,否则返回false。这个宏是在2.6.11中第一次定义的,在//之前的内核中是没有的。