7.2中断屏蔽
中断屏蔽的使用方法为:
local_irq_disable(); //开中断
....
critical section //临界区
......
local_irq_enable(); //关中断
以上两个只能对本CPU内的中断起作用,SMP多CPU并不能解决竞态
local_bh_disable()//关中断低半部
local_bh_enable()//开中断低半部
local_irq_save();//关中断并保存状态字
local_irq_restore();//开中断并恢复状态
7.3.1原子打操作
1.整型原子操作
atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0
void atomic_set(atomic_t *v, int i); //设置原子变量的值为i
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); //原子变量增加1
void atomic_dec(atomic_t *v); //原子变量减少1
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);
6.操作并返回
int atomic_add_return(int i, atomic_t *v);
int atomic_sub_return(int i, atomic_t *v);
int atomic_inc_return(atomic_t *v);
int atomic_dec_return(atomic_t *v);
7.3.2位原子操作
1.设置位
void set_bit(nr, void *addr); //置位addr地址的第nr位,即对应位写为1。
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地址的第nr位的值。
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);
应用实例:
atomic_t enable;
atomic_set(&enable, 0);
atomic_read(&enable);
7.4.1自旋锁
linux系统中与自旋锁相关的操作主要有如下4种:
1.定义自旋锁
spinlock_t spin;
2.初始化自旋锁
spin_lock_init(lock); //该宏用于动态初始化自旋锁lock
3.获得自旋锁
spin_lock(lock); //该宏用于获得自旋锁lock,如果能够立即获得锁,它就马上返回,否则,它将自旋在那里,
直到该自旋锁的保持者释放;
spin_trylock(lock);//该宏用于尝试获得自旋锁lock,如果能够立即获得锁,它获得锁并返回真,否则立即返回
假,实际上不再“原地打转”;
4.释放自旋锁
spin_unlock(lock);//该宏用于释放自旋锁lock,它与spin_lock或spin_trylock配对使用。
自旋锁一般这样被使用:
spinlock_t lock;
spin_lock_init(&lock);
spin_lock(&lock); //获得自旋锁,保护临界区
.....//临界区
spin_unlock(&lock); //解锁
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_unlock_irqrestore() = spin_unlock() + local_irq_restore()
spin_lock_bh() = spin_lock() + local_bh_disable()
spin_unlock_bh() = spin_unlock() + local_bh_enable()
7.5.1 信号量的使用
信号量只有得到信号量的进程才能执行临界区代码,但是与自旋锁不同的是,当获取不到信号量时,
进程不会原地打转而是进入休眠等待状态。
1.定义信号量
struct semaphore sem;
2.初始化信号量
void sema_init(struct semaphore *sem, int val);
void init_MUTEX(struct semaphore *sem); // sem 1
void init_MUTEX_LOCKED(struct semaphore *sem); // sem 0
DECLARE_MUTEX(name)
DECLARE_MUTEX_LOCKED(name)
3.获得信号量
void down(struct semaphore *sem); //该函数用于获得信号量sem 它会导至处睡眠,所以不能在上下文中使用
int down_interruptible(struct semaphore*sem);
int down_trylock(struct semaphore *sem); //可以在上下文中使用
4.释放信号量
void up(struct semaphore *sem);
信号量的使用:
DECLARE_MUTEX(mount_sem);
down(&mount_sem); //获得信号量,保护临界区
....
临界区
....
up(&mount_sem);//释放信号量
例:
struct semaphore sem;
int xxx_init(void)
{
...
init_MUTEX(&sem);
...
}
int xxx_open(struct inode *inode, struct file *file)
{
....
down(&sem);
/*临界资源*/
....
return 0
}
int xxx_release(struct inode *inode, struct file *file)
{
...
up(&sem); //
...
}
7.5.3完成量用于同步
1.定义完成量
struct completion my_completion;
2.初始化completion
init_completion(&my_completion);
DECLARE_COMPLETION(my_completion);
3.等待完成量
void wait_for_completion(struct completion *c);
4.唤醒完成量
void complete(struct completion *c);
void complete_all(strcut completion *c);
执行单元A 执行单元B
struct completion com;
init_completion(&com);
代码区域a 激活 代码区域c
wait_for_completion(&sem); <------------complete(&com);
.....
......;
代码区域b
struct completion ps_comple;
//in probe
init_completion(&ps_comple);
//定义并初始化completion 等同于做了上两行代码的效果
//DECLARE_COMPLETION(completion);
//in resume
INIT_COMPLETION(ps_comple); //重新初始化completion
//write
complete(&ps_comple);
//read
if(wait_for_completion(&ps_comple))
//read 可中断的 等待完成量
if(wait_for_completion_interruptible(&ts->fw_completion))
wait_for_completion_interruptible_timeout
wait_for_completion_timeout
7.6互斥体
定义互斥体并初始化
struct mutex my_mutex;
mutex_init(&my_mutex);
获取互斥体
void fastcall mutex_lock(strcut mutex *lock);
int fastcall mutex_lock_interruptible(struct mutex *lock);
int fastcall mutex_trylock(struct mutex *lock);
释放互斥体
void fastcall mutex_unlock(struct mutex *lock);
mutex 的使用方法和信号量用于互斥的场合完全一样,
struct mutex my_mutex;
mutex_init(&my_mutex);
mutex_lock(&my_mutex);
....//临界资源
mutex_unlock(&my_mutex);
mutex_destroy(&my_mutex);