1.并发与竞态
并发指的是多个执行单元同时、并行被执行,而并发的执行单元对共享资源(全局变量、静态变量)的访问容易导致竞态。
2.中断屏蔽
中断屏蔽使用方法:
local_irq_disable() //屏蔽中断
…………… //临界区
local_irq_enable() //开中断
local_irq_disable()和local_irq_enable()只能禁止和全能本CPU内
的中断;local_irq_save(flags)除了进行禁止中断操作外,还保存目前CPU
中断位信息,local_irq_restore(flags)进行与local_irq_save(flags)相
反操作
3.原子操作
原子操作指的是在执行过程中不会被别的代码路径所中断的操作
3.1 整形原子操作
1.设置原子变量的值
void atomic_set(atomic_t *v , int i); //设置原子变量的值为i
atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0
2.获取原子变量的值
atomic_read(atomic_t *v); //返回原子变量的值
3.原子变量加/减
void atomic_add(int i , atomic_t *v);//原子变量增加i
void atomic_sub(int i , atomic_t *v);//原子变量减少i
4.原子变量自增/自减
void atomic_inc(atomic_t *v); //原子变量增加i
void atomic_dec(atomic_t *v); //原子变量减少i
5.操作并测试
int atomic_inc_and_test(atomic_t *v); //自增并测试
int atomic_dec_and_test(atomic_t *v); //自减并测试
int atomic_sub_and_test(int i , atomic_t *v); //减并测试
上述是测试其是否为0,为0返回true,否则返回false
6.操作并返回
int atomic_add_return(int i , atomic_t *v);
int atomic_sub_return(int i , atomic_t *v);
int atomic_inc_return(int i , atomic_t *v);
int atomic_dec_return(int i , atomic_t *v);
上述操作对原子变量进行加/减和自增/减操作,并返回新的值
3.2 位原子操作
1.设置位
void set_bit(nr , void *addr);
2.清除位
void clear_bit(nr , void *addr);
上述操作清除addr地址的第nr位,所谓清除位即是将位写为0
3.改变位
void change_bit(nr , void *addr);
上述操作清除addr地址的第nr位进行反置
4.测试位
test_bit(nr , void *addr);
上述操作返回addr地址的第n位
5.测试并操作位
int test_and_set_bit(nr , void *addr);
int test_and_clear_bit(nr , void *addr);
int test_and_change_bit(nr , void *addr);
上述test_and_xxx_bit(nr , void *addr)操作等同于执行test_bit(nr ,
void *addr)后再执行xxx_bit(nr , void *addr)
4.自旋锁(spin lock)
自旋锁是一种典型的对临界资源进行互斥访问的手段。理解自旋锁最简单的方法就是把它当作一个变量来看。
Linux中与自旋锁相关的操作有4种:
1.定义自旋锁
spinlock_t lock;
2.初始化自旋锁
spin_lock_init(lock); //用于动态初始化自旋锁
3.获得自旋锁
spin_lock(lock);和 spin_trylock(lock);
前者如果立即获得锁,就马上返回,否则自旋在那;后者如果立即获
得锁,它获得锁并返回真,否则立即返回假,不在原地打转
4.释放自旋锁
spin_unlock(lock);//与spin_lock和spin_trylock配对使用
5.自旋锁一般使用方法(*)
spinlock_t lock;
spin_lock_init(&lock);
spin_lock(&lock);
...............
spin_unlock(&lock);
6. 自旋锁与中断的联合使用
spin_lock_irq() = spin_lock() + local_irq_disable()
spin_unlock_irq() = spin_unlock() + local_irq_enable()
spin_lock_irqsave() = spin_lock() + local_irq_save()
spin_lock_irqrestore() = spin_unlock() + local_irq_restore()
spin_lock_irq()、spin_lock_irqsave()类似函数会为自旋锁的使用
系好“安全带”以避免突入其来的中断驶入对系统的危害
5.信号量(semaphore)
5.1信号量的使用
信号量(semaphore)是用于保护临界区的一种常用方法,与自旋锁相同的是:只有得到信号量的进程才能执行临界区代码;不同的是:当获取不到信号量时,进程不会原地打转而是进入休眠等待状态。
Linux中与信号量相关的操作主要有:
1.定义信号量
struct semaphore sem; //定义名称为sem的信号量
2.初始化信号量
void sema_init(struct semaphore *sem , int val);//初始化信号
//量,并设置信号量sem的值为val
#define init_MUTEX(sem) sema_init(sem , 1) //初始化一个互斥
//的信号量,把信号量sem的值设为1
#define init_MUTEX_LOCKED(sem) sema_init(sem , 0) //初始化
//一个信号量,但它把信号量sem的值设为0
定义并初始化信号量的快捷方式:
DECLARE_MUTEX(name) 和DECLARE_MUTEX_LOCKED(name)
前者定义一个名为name的信号量并初始化为1;后者定义一个名为
name的信号量并初始化为0
3.获得信号量
void down(struct semaphore *sem);//用于获得信号量sem,它会
//导致睡眠,因此不能在上下文中断中使用
int down_interruptiable(struct semaphore *sem);//类似down
两者区别:down()而进入睡眠状态和进程不能被信号打断,但是
down_interruptiable()而进入睡眠状态能被信号打断
int down_trylock(struct semaphore *sem);//偿试获得信号量
//sem,如果立即获得,就获得该信号量并返回0,否则返回非0值
4.释放信号量
void up(struct semaphore *sem);//释放信号量,唤醒等待者
5.信号量一般使用方法
DECLARE_MUTEX(mount_sem); //定义信号量
down(&mount_sem); //获取信号量,保护临界区
............. //临界区
up(&mount_sem); //释放信号量
5.2信号量用于同步
如果信号量初始化为0,则它可以用于同步,同步意味着一个执行单元的继续执行需等待另一执行单元完成某事,保证执行的先后顺序。
5.3自旋锁VS信号量
自旋锁和信号量都是解决互斥问题的基本手段。信号量和自旋锁属于不同层次的互斥手段,前者的实现有赖于后者。
1.信号量是进程级的,进程上下文切换的开销很大,因此只有当进程占用资
源时间较长时,用信号量才是较好选择。
2.当所要保护的临界区访问时间比较短时,用自旋锁是非常方便的,因为它
节省上下文切换的时间,但CPU得不到自旋锁会在原地打转,所以要求锁
不能在临界区长时间停留,否则会降低系统的效率。
3.信号量所保护的临界区可包含可能引起阻塞的代码,而自旋锁则绝对要避
免用来保护包含这样代码的临界区。因为阻塞意味着要进行进程切换,如
果进程被切换出去后,另一个进程企图获取本自旋锁,死锁就会发生。
6.互斥体
定义名为my_mutex的互斥体并初始化:
struct mutex my_mutex; //定义互斥体
mutex_init(&my_mutex); //初始化互斥体
获取互斥体:
void inline __sched mutex_lock(struct mutex *lock);
int __sched mutex_lock_interruptible(struct mutex *lock);
mutex_lock()和mutex_lock_interruptible()的区别和down()和down_ interruptible ()的区别完全一样,前者引起的睡眠不能被信号打断,而后者可以。
释放互斥体:
void __sched mutex_unlock(struct mutex *lock);
互斥体的使用方法:
struct mutex my_mutex; //定义mutex
mutex_init(&my_mutex); //初始化mutex
mutex_lock(&my_mutex); //获取mutex
................ //临界资源
mutex_unlock(&my_mutex);//释放mutex