首页 > 学院 > 开发设计 > 正文

Linux设备驱动的并发控制总结

2019-11-08 00:07:27
字体:
来源:转载
供稿:网友

1.linux驱动为什么存在并发控制?

答:并发( concurrency)指的是多个执行单元同时、并行被执行,而并发的执行单元对共享资源(硬件资源和软件上的全局变量、静态变量等)的访问则很容易导致竞态( race conditions),而在linux设备驱动中,会存在多个执行单元对共享资源的访问,就会导致竞态,导致系统紊乱,因此需要增加并发控制。

2.在哪些条件下容易发生竞态?

答:有以下情况:                           (1).SMP(对称多处理器)的多个CPU。                           (2).单个CPU内进程与抢占它的进程。                           (3).中断(硬中断、软中断、Tasklet、中断底半部)与进程之间。

3.linux中解决竟态的方法有哪些?

答:中断屏蔽、原子操作、自旋锁(读写自旋锁、顺序所、RCU(读-拷贝-更新))、信号量。

4.上述解决linux竟态方法的操作机制是?

答:中断屏蔽:由于linux内核的进程调度等操作都依赖中断来实现,内核抢占进程之间的并发就可以避免。       原子操作:原子操作在执行过程中不会被别的代码路径所中断的操作,因此内核代码可以安全调用他们而不被打断。       自旋锁:为了获得一个自旋锁, 在某 CPU 上运行的代码需先执行一个原子操作,该操作测试并设置 test-and-set) 某个内存变量,                       由于它是原子操作,所以在该操作完成之前其他执行单元不可能访问这个内存变量。       信号量:信号量( semaphore)是用于保护临界区的一种常用方法,它的使用方式和自旋锁类似。与自旋锁相同,只有得到信号量的                      进程才能执行临界区代码

5.各方法在linux驱动适用的坏境?

答:中断屏蔽:单CPU范围内。       原子操作:ALL.       自旋锁:对 SMP 或单 CPU 但内核可抢占的情况,对于单 CPU 和内核不支持抢占的系统, 自旋锁退化为空操作。在单 CPU 和内核                        可抢占的系统中,自旋锁持有期间内核的抢占将被禁止。       信号量:ALL.        

6.各方法具体的API操作?

答:(1).中断屏蔽 

              local_irq_disable() //屏蔽中断          local_irq_enble() //开启中断。

       (2).原子操作

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); /* 原子变量增加 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);

       (3).自旋锁

1.定义自旋锁spinlock_t lock;2.初始化自旋锁spin_lock_init(lock)该宏用于动态初始化自旋锁 lock。3.获得自旋锁spin_lock(lock)该宏用于获得自旋锁 lock,如果能够立即获得锁,它就马上返回,否则,它将自旋在那里,直到该自旋锁的保持者释放。spin_trylock(lock)该宏尝试获得自旋锁 lock,如果能立即获得锁,它获得锁并返回真,否则立即返回假,实际上不再“在原地打转”。4.释放自旋锁spin_unlock(lock)该宏释放自旋锁 lock,它与 spin_trylock 或 spin_lock 配对使用。

       (4).自旋锁之读写锁

1.定义和初始化读写自旋锁rwlock_t my_rwlock = RW_LOCK_UNLOCKED; /* 静态初始化 */rwlock_t my_rwlock;rwlock_init(&my_rwlock); /* 动态初始化 */2.读锁定void read_lock(rwlock_t *lock);void read_lock_irqsave(rwlock_t *lock, unsigned long flags);void read_lock_irq(rwlock_t *lock);void read_lock_bh(rwlock_t *lock);3.读解锁void read_unlock(rwlock_t *lock);void read_unlock_irqrestore(rwlock_t *lock, unsigned long flags);void read_unlock_irq(rwlock_t *lock);void read_unlock_bh(rwlock_t *lock);4.写锁定void write_lock(rwlock_t *lock);void write_lock_irqsave(rwlock_t *lock, unsigned long flags);void write_lock_irq(rwlock_t *lock);void write_lock_bh(rwlock_t *lock);int write_trylock(rwlock_t *lock);5.写解锁void write_unlock(rwlock_t *lock);void write_unlock_irqrestore(rwlock_t *lock, unsigned long flags);void write_unlock_irq(rwlock_t *lock);void write_unlock_bh(rwlock_t *lock);

     (5).读写锁之顺序锁

写执行单元涉及的顺序锁操作如下:1.获得顺序锁void write_seqlock(seqlock_t *sl);int write_tryseqlock(seqlock_t *sl);write_seqlock_irqsave(lock, flags)write_seqlock_irq(lock)write_seqlock_bh(lock)其中:write_seqlock_irqsave() = loal_irq_save() + write_seqlock()write_seqlock_irq() = local_irq_disable() + write_seqlock()write_seqlock_bh() = local_bh_disable() + write_seqlock()2.释放顺序锁void write_sequnlock(seqlock_t *sl);write_sequnlock_irqrestore(lock, flags)write_sequnlock_irq(lock)write_sequnlock_bh(lock)其中:write_sequnlock_irqrestore() = write_sequnlock() + local_irq_restore()write_sequnlock_irq() = write_sequnlock() + local_irq_enable()write_sequnlock_bh() = write_sequnlock() + local_bh_enable()读执行单元涉及的顺序锁操作如下:1.读开始unsigned read_seqbegin(const seqlock_t *sl);read_seqbegin_irqsave(lock, flags);2.重读int read_seqretry(const seqlock_t *sl, unsigned iv);read_seqretry_irqrestore(lock, iv, flags);

      (6).RCU(读-拷贝-更新)

1.读锁定rcu_read_lock()rcu_read_lock_bh()2.读解锁rcu_read_unlock()rcu_read_unlock_bh()3.同步 RCUsynchronize_rcu()

(7).信号量

1.定义信号量下列代码定义名称为 sem 的信号量:struct semaphore sem;2.初始化信号量void sema_init(struct semaphore *sem, int val);3.获得信号量void down(struct semaphore * sem);该函数用于获得信号量 sem,它会导致睡眠,因此不能在中断上下文使用;4.释放信号量void up(struct semaphore * sem);该函数释放信号量 sem,唤醒等待者。

(8).信号量之完成量

1.定义完成量下列代码定义名为 my_completion 的完成量:struct completion my_completion;2.初始化 completion下列代码初始化 my_completion 这个完成量:init_completion(&my_completion);对 my_completion 的定义和初始化可以通过如下快捷方式实现:DECLARE_COMPLETION(my_completion);3.等待完成量下列函数用于等待一个 completion 被唤醒:void wait_for_completion(struct completion *c);4.唤醒完成量下面两个函数用于唤醒完成量:void complete(struct completion *c);void complete_all(struct completion *c);        
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表