{//?什么是并发,为何要使用并发机制 并发即是 多件事情同时在执行 只有使这些设备都并发的执行才能满足性能要求。 例: 如果系统上挂10个设备,每个设备都请求,如果是串行顺序执行, 可能一个设备要等较长时间,系统才能响应它 } {//?如何实现并发 CPU是顺序的读入指令执行的, 如何来实现并发呢? 例: 当你A先生的业务时,B女士来个电话,你接完电话后继续做A的事。 如何你切换足够快,即在A,B的忍耐时间内。 感觉就像在并发执行一样。 使用中断的方式可实现并发 //中断: 类似于接电话,打断当前执行,等处理完后,返回再接着执行。 } {//?为什么要进行并发控制 并发会导致竞态的发生。 //竞态: 一个资源被并发执行的任务同时访问时,就会出现竞争。此时的状态就是竞态。 需保证一个资源在一个时间只能被一个任务访问,才能避免混乱。即并发控制 } {//?如何进行并发控制 采用互斥机制对并发进行控制 //互斥: 共享资源被某任务访问时,别的任务禁止访问。 互斥机制: {//中断屏蔽 使用禁止中断方式,避免中断的影响 local_irq_disable //屏蔽中断 临界区代码 //临界区: 访问共享资源的代码区域 local_irq_enable //开中断 注: 1。屏蔽中断的时间尽量短,否则会造成别的中断延时过久,甚至丢失,最好能采有屏蔽指定中断的方式 disable_irq(int irq); //屏蔽指定中断号的中断 enable_irq(int irq); //使能某中断号的中断 2。常需保存当前的中断状态,便于恢复 用local_irq_save(flags); 代替local_irq_disable 用local_irq_restore(flags) 代替 local_irq_enable } {//原子操作 并发中不被打断的最小单元 {//---hello_atomic/hello.c 实现设备只被一个进程打开 #include <asm/atomic.h> static atomic_t hello_atomic = ATOMIC_INIT(1); //定义原子变量hello_atomic ,并初始化为1 static int hello_open(struct inode *inode,struct file *file) { if (!atomic_dec_and_test(&hello_atomic)) { // atomic_dec_and_test表示原子变量自减一,并测试是否为了零,如果为零返回真 //当已open过,还未release时,再次open , hello_atomic为0, 再减一不为零,!atomic_dec_and_test 成立 atomic_inc(&hello_atomic); //原子变量加一,恢复自减前状态 return - EBUSY; //已经被打开 } //当第一次被open时, hello_atomic为1 , !atomic_dec_and_test 不成立, 正常打开 printk("hello open \n"); return 0; } static int hello_release(struct inode *inode,struct file *file) { atomic_inc(&hello_atomic); //释放设备 printk("hello release\n"); return 0; } } } {//自旋锁 spinlock 死循环空转CPU 等待释放锁, 不睡眠, 适用于锁持有时间小于睡眠唤醒时间场合 {//---hello_spinlock/hello.c static spinlock_t hello_spinlock; static int hello_resource = 1; static int hello_open(struct inode *inode,struct file *file) { spin_lock(&hello_spinlock); //还可和中断屏蔽合用 spin_lock_irq if(hello_resource == 0) { spin_unlock(&hello_spinlock); return - EBUSY; } hello_resource--; spin_unlock(&hello_spinlock); printk("hello open \n"); return 0; } static int hello_release(struct inode *inode,struct file *file) { spin_lock(&hello_spinlock); hello_resource++; spin_unlock(&hello_spinlock); printk("hello release\n"); return 0; } } {//读写锁 rwlock_t 它是从资源访问的特性上,对锁进行了优化, 读可同时进行 ,读写互斥 } {//顺序锁 seqlock 它是对读写锁的进一步优化,放开了读写互斥, 即仅写间互斥。即使读者正在读的时候也允许写者继续运行 } {//无锁设计 如环形缓冲 类似生产者和消费者模型 } //加锁粒度 } {//信号量 进程当中用于并发互斥和,资源的计数。 相对于自旋锁,信号量会睡眠,仅能用于进程中 //---hello_semaphore/hello.c #include <linux/semaphore.h> static DECLARE_MUTEX(hello_semlock); //定义一个初始值为一的信号量 static int hello_open(struct inode *inode,struct file *file) { if (down(&hello_semlock)) /* 获得打开锁*/ { return - EBUSY; /* 设备忙*/ } printk("hello open \n"); return 0; } static int hello_release(struct inode *inode,struct file *file) { up(&hello_semlock); /* 释放打开锁*/ printk("hello release\n"); return 0; } } {//互斥体 互斥体是专门用来做互斥的, 和二元的信号量类似, struct mutex my_mutex; /* 定义mutex */ mutex_init(&my_mutex); /* 初始化mutex */ mutex_lock(&my_mutex); /* 获取mutex */ .../* 临界资源*/ mutex_unlock(&my_mutex); /* 释放mutex */ } } {//?并发机制使用场合 1. 中断屏蔽的使用场合 当有中断处理程序访问共享资源的时候。 2. 原子操作的使用场合 只使用于共享资源为一个变量的操作的情况 3. 自旋锁的使用场合 在临界区代码运行时间比较短的情况。 多CPU的情况下 4. 信号量的使用场合 临界区代码运行时间比较长的情况。 当锁持有的时间不是很长的时候,优先使用信号量。 1注意: 中断里不能使用信号量。 因为中断不能睡眠。 } }
linux设备驱动中的并发控制,布布扣,bubuko.com
原文:http://blog.csdn.net/it_liuwei/article/details/23952333