Linux设备中的并发控制

原创 2012年09月20日 09:04:40

并发执行的唯一原因是:硬件中断服务。内核代码是可抢占的。
什么是竞争?当 2 个执行的线路[有机会操作同一个数据结构(或者硬件资源), 混合的可能性就一直存在。
避免竞争方法:
       在你设计驱动时在任何可能的时候记住避免共享的资源. 如果没有并发存取, 就没有竞争情况. 因此小心编写的内核代码应当有最小的共享. 这个想法的最明显应用是避免使用全局变量. 如果你将一个资源放在多个执行线路能够找到它的地方, 应当有一个很强的理由这样做。全局变量不是共享资源的唯一方法,传递一个指针给内核的其他代码,潜在的创造了一个新的共享形式。
       存取管理的常用技术是加锁或者互斥,确保在任何时间内只有一个执行线程可以操作一个共享资源。
当内核代码创建一个会被内核其他部分共享的对象时, 这个对象必须一直存在(并且功能正常)到它知道没有对它的外部引用存在为止。
临界区:在任何给定的时间内只有一个线程可以执行代码。
旗标(信号量):是一个整型值,结合一对函数,一个像进入临界区的进程将调用相关旗标的P,如果旗标的值大于0,这个值将减一并且继续进程。相反,如果旗标的值是0(或者更小),进程必须等待别的进程释放旗标,解锁旗标通过调用V完成,这个函数会增加旗标的值,并且。如果需要,可以唤醒等待的进程。
当旗标初始化为1时,就成了互斥锁。
初始化:void sema_init(struct semaphore *sem, int val)    /* val 表示初始化值 */
互斥锁初始化: DECLARE_MUTEX(name);              /* 1 name为信号量变量*/
                            DECLARE_MUTEX_LOCKED(name);       /* 0 同上*/ 
动态初始化(运行时):
void init_MUTEX(struct semaphore *sem);
void init_MUTEX_LOCKED(struct semaphore *sem);
P函数成为down—或者这个名字的变体:作用是是信号量减一,并且可能使调用者睡眠一会,等到旗标变为可用之后,再对共享资源进行存取。
void down(struct semaphore * sem);          /* 递减信号量,并等待需要的时间 */
int down_interruptible(struct semaphore *sem); /* 可被中断的:允许一个在等待用户空间的进程被用户中断 */
int down_trylock(struct semaphore *sem);     /* 从不睡眠 */
V函数:void up(struct semaphore *sem);  /* 当持有一个旗标时遇到一个错误时,旗标必须在返回错误状态之前释放旗标。
注意:旗标必须在设备对系统的其他部分可用前初始化。
read and write semaphore:
down_read(struct rm_semaphore *sem);  --------  down_write(struct rm_semaphore *sem)
int down_read_trylock(struct rw_semaphore *sem);  -----  down_write_trylock(struct rw_semaphore *sem);
void up_read(struct rw_semaphore *sem);  ---- void up_write(struct rw_semaphore *sem);
void downgrade_write(struct rw_semaphore *sem); //一旦完成改变后允许其他read进入。
what is the meaning of Completions?
允许一个线程告诉另一个线程工作已经完成。
一个completion的创建:
<linux/completion.h>
DDECLARE_COMLETION(my_completion);
动态创建和初始化:
struct completion my_completion;
init_completion( &my_completion);
简单的调用:
void wait_for_completion(struct completion *c)  //如果没有人完成这个任务,结果会是一个不可杀死的进程。
一般调用:
void complete(struct completion *c);   /* 一个等待进程 */
void complete_all(struct completion *c); /* 多个等待进程 */
what is the meaning of spinlock?
background: 大部分加锁是有一种自旋锁机制来实现;
special case:自旋锁可用在不能睡眠的代码中,例如中断处理;
concept:互斥设备,上锁和解锁;如果锁是可用的, 这个"上锁"位被置位并且代码继续进入临界区. 相反, 如果这个锁已经被别人获得, 代码进入一个紧凑的循环中反复检查这个锁, 直到它变为可用. 这个循环就是自旋锁的"自旋"部分。(简单的形式并不是好的形势)
要求:原子操作;在超线程上避免死锁。
#include<linux/spinlock.h>
初始化定义:spinlock_t my_lock = SPIN_LOCK_UNLOCKED;
或者在运行时使用:void spin_lock_init(spinlock_t *lock);
在进入一个临界区时,代码必须获得需要的lock:
void spin_lock(spinlock_t *lock);  /* 由于不可中断 自旋直到锁变为可用*/
释放锁:
void spin_unlock(spinlock_t *lock);
原则上:不能睡眠;不能因为任何原因放弃处理器,除了服务中断(并且有时即便如此也不行);自旋锁必须一直是尽可能短时间得持有。
原因:内核抢占;睡眠可能发生在从用户空间拷贝数据,分配内存的任何操作等等;中断在获得自旋操作之后,但是中断操作中的代码又需要获得这把锁,这就会发生永久的自旋。(避免这个陷阱需要在持有自旋锁时禁止中断)
void spin_lock(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
void spin_lock_irq(spinlock_t *lock);
void spin_lock_bh(spinlock_t *lock)
void spin_unlock(spinlock_t *lock);
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
void spin_unlock_irq(spinlock_t *lock);
void spin_unlock_bh(spinlock_t *lock);
陷阱锁:模糊的规则 加锁顺序规则 细 – 粗 – 粒度加锁
原子变量:<asm/atomic.h>
void atomic_set(atomic_t *v, int i); 
atomic_t v = ATOMIC_INIT(0); 
设置原子变量 v 为整数值 i. 你也可在编译时使用宏定义 ATOMIC_INIT 初始化原子值.
int atomic_read(atomic_t *v); 
返回 v 的当前值.
void atomic_add(int i, atomic_t *v); 
由 v 指向的原子变量加 i. 返回值是 void, 因为有一个额外的开销来返回新值, 并且大部分时间不需要知道它.
void atomic_sub(int i, atomic_t *v); 
从 *v 减去 i.
void atomic_inc(atomic_t *v); 
void atomic_dec(atomic_t *v); 
递增或递减一个原子变量.
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, 那么返回值是真; 否则, 它是假. 注意没有 atomic_add_and_test.
int atomic_add_negative(int i, atomic_t *v); 
加整数变量 i 到 v. 如果结果是负值返回值是真, 否则为假.
位操作:<asm/bitops.h>
void set_bit(nr, void *addr); 
设置第 nr 位在 addr 指向的数据项中.
void clear_bit(nr, void *addr); 
清除指定位在 addr 处的无符号长型数据. 它的语义与 set_bit 的相反.
void change_bit(nr, void *addr); 
翻转这个位.
test_bit(nr, void *addr); 
这个函数是唯一一个不需要是原子的位操作; 它简单地返回这个位的当前值.






Linux 设备驱动的并发控制

Linux 设备驱动中必须要解决的一个问题是多个进程对共享的资源的并发访问,并发的访问会导致竞态,即使是经验丰富的驱动工程师也常常设计出包含并发问题bug 的驱动程序。 一、基础概念 1、Linu...
  • zqixiao_09
  • zqixiao_09
  • 2016年03月15日 19:26
  • 2593

《Linux4.0设备驱动开发详解》笔记--第七章:Linux设备中的并发控制

7.1 并发与竞态 并发是指多个执行单元同时、并发的被执行,而并发的执行单元对共享资源(硬件资源、软件上的的全局变量、静态变量等)的访问则很容易导致竟态 竟态发生在以下几种情况 对称多处理器(SMP...
  • z1106609486
  • z1106609486
  • 2016年05月19日 14:37
  • 3639

Linux设备驱动开发详解总结(二)之并发与竞争

Linux设备驱动中必须解决一个问题是多个进程对共享资源的并发访问,并发的访问会导致竞态,在当今的Linux内核中,支持SMP与内核抢占的环境下,更是充满了并发与竞态。幸运的是,Linux 提供了多钟...
  • lwj103862095
  • lwj103862095
  • 2013年01月28日 16:53
  • 2593

kk-并发控制和处理

什么是并发,竞态竞态的解决方式实际中如何灵活应用   ## 什么是并发,竞态 并发(concurrency): 并发是指多个执行单元同时,并行的执行竞态(race conditions): 并发的执...
  • xiaow_shine
  • xiaow_shine
  • 2016年03月10日 11:19
  • 153

[Linux]Linux Shell多进程并发以及并发数控制

Unix是一个多任务系统,允许多用户同时运行多个程序。shell的元字符&提供了在后台运行不需要键盘输入的程序的方法。输入命令后,其后紧跟&字符,该命令就会被送往到linux后台执行,而终端又可以继续...
  • yeweiouyang
  • yeweiouyang
  • 2016年09月12日 12:56
  • 10578

Linux 设备驱动的并发控制

Linux 设备驱动中必须要解决的一个问题是多个进程对共享的资源的并发访问,并发的访问会导致竞态,即使是经验丰富的驱动工程师也常常设计出包含并发问题bug 的驱动程序。 一、基础概念...
  • qq_21593899
  • qq_21593899
  • 2016年06月19日 11:39
  • 172

Linux设备驱动中的并发控制

并发与竞态 解决竞态问题的途径是保证对共享资源的互斥访问。 访问共享资源的代码区域称为临界区,临界区需要以某种互斥机制加以保护。中断屏蔽、原子操作、自旋锁和信号量等是Linux设备驱动中可采...
  • zongguo
  • zongguo
  • 2013年04月03日 20:24
  • 358

linux设备驱动中的并发控制

在linux设备驱动中必须解决的一个问题是多个进程对互斥资源的并发访问,并发的访问会导致竞态。 1.1 并发与竟态 并发指多个执行单元同时、并发的被执行,而并发的执行单元对共享资源的访问很容易导致竟态...
  • c1194758555
  • c1194758555
  • 2017年02月03日 17:40
  • 284

Linux设备驱动中的并发控制

并发(concurrency)指的是多个执行单元同时、并行被执行。而并发的执行单元对共享资源(硬件资源和软件上的全局、静态变量)的访问则容易导致竞态(race conditions)。 SMP是一种...
  • lzc89
  • lzc89
  • 2017年04月20日 15:02
  • 109

linux设备驱动之并发控制

一、基本概念       并发是指多个执行单元同时、并行被执行,而并发的单元对共享资源(硬件资源和软件上的全局变量、静态变量等)的访问很容易导致静态。 二、产生竞态的情况     主要有三种情况:1...
  • xzp8891
  • xzp8891
  • 2013年12月02日 09:26
  • 481
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux设备中的并发控制
举报原因:
原因补充:

(最多只允许输入30个字)