互斥锁
引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
互斥锁的操作
1.定义互斥锁变量 pthread_mutex_t
2.初始化互斥锁变量 pthread_mutex_init
3.加锁 pthread_mutex_lock
4.解锁 pthread_mutex_lock
5.销毁互斥锁 pthread_mutex_destory
创建: int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr) 其中mutexattr用于指定互斥锁属性,如果为NULL则使用缺省属性。
获取锁:int pthread_mutex_lock(pthread_mutex_t *mutex) 在锁已经被占据时返回挂起等待
销毁:int pthread_mutex_destroy(pthread_mutex_t *mutex)
销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开放状态。
由于在Linux中,互斥锁并不占用任何资源,pthread_mutex_destroy()除了检查锁状态以外(锁定状态则返回EBUSY)没有其他动作。。
释放锁:int pthread_mutex_unlock(pthread_mutex_t *mutex)
*非阻塞加锁:int pthread_mutex_trylock(pthread_mutex_t *mutex) 在锁已经被占据时返回EBUSY
自旋锁(Spin lock)
自旋锁是专为防止多处理器并发而引入的一种锁,它在内核中大量应用于中断处理等部分
循环判断条件是否满足,反应及时,但是CPU消耗较高,适用于阻塞时间很短的等待
为实现保护共享资源而提出一种锁机制.自旋锁类似于互斥锁,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁
自旋锁的操作
1、初始化
spin_lock_init(x)
该宏用于初始化自旋锁x。自旋锁在真正使用前必须先初始化。该宏用于动态初始化。
2、加锁
void spin_lock(spinlock_t *lock);
最基本得自旋锁函数,它不失效本地中断。
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
在获得自旋锁之前禁用硬中断(只在本地处理器上),而先前的中断状态保存在flags中
void spin_lock_irq(spinlock_t *lock);
在获得自旋锁之前禁用硬中断(只在本地处理器上),不保存中断状态
void spin_lock_bh(spinlock_t *lock);
在获得锁前禁用软中断,保持硬中断打开状态
3、解锁
spin_unlock(lock);
该宏释放自旋锁lock,它与spin_trylock或者spin_lock配对使用。如果spin_trylock返回假,表明没有获得自旋锁,因此不必使用spin_unlock(lock)释放。
spin_unlock_bh(lock)
该宏释放自旋锁lock的同一时候,也使能本地的软中断。它与spin_lock_bh配对使用。
spin_unlock_irqrestore(lock, flags)
该宏释放自旋锁lock的同一时候,使能本地硬件中断并且恢复标志寄存器的值为变量flags保存的值。它与spin_lock_irqsave配对使用。
spin_unlock_irq(lock)
该宏释放自旋锁lock的同一时候,也使能本地中断。它与spin_lock_irq配对使用。
读写锁
读写锁默认读优先
使用读者写者模型 – 写互斥 , 读共享
写的时候, 别人既不能读,也不能写
读的时候可以一起读,但是不能写
若当前已经加写锁,则其他线程加写锁 / 读锁都会被阻塞若当前已经加读锁,则其他线程可以继续加读锁,但是加写锁会阻塞
读写锁的阻塞使用自旋锁实现
读写锁的操作
- 初始化和销毁:
#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
成功则返回0, 出错则返回错误编号.
同互斥量以上, 在释放读写锁占用的内存之前, 需要先通过pthread_rwlock_destroy对读写锁进行清理工作, 释放由init分配的资源.
2.读和写:
#include <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
成功则返回0, 出错则返回错误编号.
这3个函数分别实现获取读锁, 获取写锁和释放锁的操作. 获取锁的两个函数是阻塞操作, 同样, 非阻塞的函数为:
#include <pthread.h>
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
成功则返回0, 出错则返回错误编号.
非阻塞的获取锁操作, 如果可以获取则返回0, 否则返回错误的EBUSY.