linux驱动之并发与竟态

一、并发与竞态
	1、中断屏蔽
		1.1中断屏蔽使用方法
		
			local_irq_disable()	//屏蔽中断	
			.........
			critical section	//临界区
			.........
			local_irq_enable()	//开中断
			----------------------------------------
			
			local_irq_save(flags)		//除屏蔽中断外,还能保存目前CPU的中断信息
			local_irq_restore(flags)	//与上行相反的操作
			
			----------------------------------------
			
			local_bh_disable()	//禁止中断的低半部
			local_bh_enable()	//使能中断的低半部
			
			说明:上面方法只能禁止和使能本CPU内的中断,不能解决SMP多CPU引发的竟态;
			
	2、原子操作
		2.1整形原子操作
		
			2.1.1 设置原子变量的值
				void atomic_set(atomic_t *v, int i);	//设置原子变量的值为i
				atomic_t v = ATOMIC_INIT(0);			//定义原子变量V,并初始化为0
			
			2.1.2 获取原子变量的值
				atomic_read(atomic_t *v);				//返回原子变量的值
			
			2.1.3 原子变量加减
				void atomic_add(int i, atomic_t *v);	//原子变量加
				void atomic_sub(int i, atomic_t *v);	//原子变量减
				
			2.1.4 原子变量自增、自减
				void atomic_inc(atomic_t *v);
				void atomic_dec(atomic_t *v);
				
			2.1.5 操作并测试
				void atomic_inc_and_test(atomic_t *v);
				void atomic_dec_and_test(atomic_t *v);
				void atomic_sub_test_(int i, atomic_t *v);
				
			2.1.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);
			
		2.2位原子操作
		
			2.2.1 设置位
				void set_bit(nr, void *addr);		//设置addr的第nr位,即将该位写1
				
			2.2.2 清除位
				void clear_bit(nr, void *addr);		//清除addr的第nr位,即将该位写0
			
			2.2.3 改变位
				void change_bit(nr, void *addr);	//对addr的第nr位进行反置
				
			2.2.4 测试位
				test_bit(nr, void *addr);			//返回addr地址的第nr位
				
			2.2.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);
	3、自旋锁【获取不到锁时将在原地打转,占用CPU资源,用于SMP CPU、多任务,被锁临界区小,备注:一般用自旋锁解决多CPU】
		
		3.1 自旋锁的使用
		
			3.1.1 定义自旋锁
				spinlock_t spin;
				
			3.1.2 初始化自旋锁
				spin_lock_init(lock);
				
			3.1.3 获得自旋锁
				spin_lock(lock);		//在原地打转
				spin_try_lock(lock);	//获得锁就返回真,否则就返回假,不在原地打转
				
			3.1.4 释放自旋锁
				spin_unlock(lock);		//释放自旋锁
			
			虽然自旋锁可以保证临界区不受别的CPU和本CPU内的抢占进程打扰,但是得到锁的代码容易受到中断和低半部(BH)的影响,所以的到自旋锁衍生;
			3.1.5 获得自旋锁、禁止中断
				spin_lock_irq() = spin_lock() + local_irq_disable();
			
			3.1.6 释放自旋锁、释放中断
				spin_unlock_irq() = spin_unlock() + local_irq_enable();
			
			3.1.7 获得自旋锁、保存中断标识
				spin_lock_irqsave() = spin_lock() + local_irq_save();
				
			3.1.8 释放自旋锁、还原中断标识
				spin_unlock_irqrestore() = spin_unlock() + local_irq_restore();
			
			3.1.9 获得自旋锁、禁止低半部
				spin_lock_hb() = spin_lock() + local_bh_disable();
				
			3.1.10 释放自旋锁、使能低半部
				spin_unlock_hb() = spin_unlock() + local_bh_enable();
			
		3.2 读写自旋锁
			
			3.2.1 定义和初始化读写自旋锁
				rwlock_t my_rwlock = RW_LOCK_UNLOCKED;	//静态初始化
				
				rwlock_t my_rwlock;
				rwlock_init(&my_rwlock);				//动态初始化
			
			3.2.2 读锁定
				void read_lock(rwlock_t * lock);
				void read_lock_irqsave(rwlock_t *lock, unsigned long flags);
				void read_lcok_irq(rwlock_t * lock);
				void read_lcok_bh(rwlock_t * lock);
			
			3.2.3 读解锁
				void read_unlock(rwlock_t * lock);
				void read_unlock_irqsave(rwlock_t *lock, unsigned long flags);
				void read_unlcok_irq(rwlock_t * lock);
				void read_unlcok_bh(rwlock_t * lock);
				
			3.2.2 写锁定
				void write_lock(rwlock_t * lock);
				void write_lock_irqsave(rwlock_t *lock, unsigned long flags);
				void write_lcok_irq(rwlock_t * lock);
				void write_lcok_bh(rwlock_t * lock);
			
			3.2.5 写解锁
				void write_unlock(rwlock_t * lock);
				void write_unlock_irqsave(rwlock_t *lock, unsigned long flags);
				void write_unlcok_irq(rwlock_t * lock);
				void write_unlcok_bh(rwlock_t * lock);
				
		3.3 顺序锁
			3.3.1 获得顺序锁
				void write_seqlock(seqlock_t *sl);
				int write_tryseqlock(seqlock_t *sl);
				void write_seqlock_irqsave(seqlock_t *sl, flags);
				int write_seqlock_irq(seqlock_t *sl);
				int write_seqlock_bh(seqlock_t *sl);
				
			3.3.2 释放顺序锁
				void write_sequnlock(seqlock_t *sl);
				int write_trysequnlock(seqlock_t *sl);
				void write_sequnlock_irqsave(seqlock_t *sl, flags);
				int write_sequnlock_irq(seqlock_t *sl);
				int write_sequnlock_bh(seqlock_t *sl);
			
	
	4、信号量【获取不到锁时将进入休眠,不占用CPU资源, 用于SMP CPU、多任务,被锁临界区大,备注:用于多个进程之间对资源的互斥】
		
		4.1 信号量的使用
			
			4.1.1 定义信号量
				struct semaphore sem;
			
			4.1.2 初始化信号量
				void sema_init(struct semaphore *sem, int val);		//初始化信号量,并设置信号量的值为val
				void init_MUTEX(struct semaphore *sem);				//初始化信号量,并设置信号量为1
				void init_MUTEX_LOCKED(struct semaphore *sem);		//初始化信号量,并设置信号量为0
				下面是定义并初始化信号量的“快捷方式”
				DECLARE_MUTEX(name);
				DECLARE_MUTEX_LOCKED(name);
				
			4.1.3 获得信号量
				void down(struct semaphore *sem);					//该函数用于获得信号量,会导致休眠,不能用于中断上下文
				int down_interruptible(struct semaphore *sem);		//该函数用于获得信号量,会导致休眠,可以中断
				int down_trylock(struct semaphore *sem);
				
			4.1.4 释放信号量
				void up(struct semaphore *sem);
				
			4.1.5 读写信号量
				
				4.1.5.1 定义和初始化读写信号量
					
					struct rw_semaphore my_rws;						//定义信号量
					void init_rwsem(struct rw_semaphore *sem);		//初始化信号量
				
				4.1.5.2 读信号量获取
					void down_read(struct rw_semaphore *sem);
					int down_read_trylock(struct rw_semaphore *sem);
				
				4.1.5.3 读信号量释放
					void up_read(struct rw_semaphore *sem);
					
				4.1.5.4 写信号量获取
					void down_write(struct rw_semaphore *sem);
					int down_write_trylock(struct rw_semaphore *sem);
				
				4.1.5.5 写信号量释放
					void up_write(struct rw_semaphore *sem);
	
	5、完成量用于同步【比信号量更好的同步机制】
	
	6、互斥体
		
		6.1 定义并初始化
			struct mutex my_mutex;
			mutex_init(&my_mutex);
		
		6.2 获取互斥体
			void fastcall mutex_lock(struct mutex *lock);
			void fastcall mutex_lock_interruptible(struct mutex *lock);
			void fastcall mutex_trylock(struct mutex *lock);
			
		6.3 释放互斥体
			void fastcall mutex_unlock(struct mutex *lock);
	
	
			


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值