并发与并行
并发是指一个处理器同时处理多个任务。
并行是指多个处理器或者是多核的处理器同时处理多个不同的任务。
并发是逻辑上的同时发生(simultaneous),而并行是物理上的同时发生。
来个比喻:并发是一个人同时吃三个馒头,而并行是三个人同时吃三个馒头。
并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行。就好像两个人各拿一把铁锨在挖坑,一小时后,每人一个大坑。所以无论从微观还是从宏观来看,二者都是一起执行的。
并发与竞态:
那些可能会引起竞态
1、多个应用层序(进程)访问驱动
2、对称多处理器(SMP)的多个CPU
3、单CPU内进程与抢占它的进程 Linux 2.6内核支持抢占调度,一个进程在内核执行的时候可能被另一高优先级进程打断,
进程与抢占它的进程访问共享资源的情况类似于SMP的多个CPU。
4、中断(硬中断、软中断、Tasklet、底半部)与进程之间中断可以打断正在执行的进程,
如果中断处理程序访问进程正在访问的资源,则竞态也会发生。
**
内核阶段如何去处理竞态: ---- 五套机制
1、中断屏蔽
2、原子变量
3、自旋锁
4、信号量
5、互斥体
不同的机制有不同的特点和应用场景。
1、中断屏蔽
屏蔽中断容易导致kenel down掉,不推荐使用,如果要使用的话,临界区的操作应尽可能的短
—>只能够屏蔽当前CPU
屏蔽中断
local_irq_disable() /* 屏蔽中断 /
critical section / 临界区*/
开启中断
local_irq_enable() /* 开中断*/
屏蔽中断的时候把中断状态保存
local_irq_save(flags)
critical section /* 临界区*/
开启中断,并回复中断状态
local_irq_restore(flags)
注意:local_irq_disable()和local_irq_enable()都只能禁止和使能本CPU内的中断,因此,并不能解决SMP多CPU引发的竞态
2、原子变量
特点:最小的可操作单位 原子操作 atomic 适用于变量,操作不可分割或被打断
atomic_t
本质:typedef struct {
int counter;
} atomic_t;
1、变量的定义
atomic_t myatomic;
2、变量的初始化
#define ATOMIC_INIT(i) { (i) }
#define atomic_set(v,i) (((v)->counter) = (i))
atomic_set(myatomic,1);
3、加锁-解锁
#define atomic_inc(v) atomic_add(1, v) //变量值加1
#define atomic_dec(v) atomic_sub(1, v) //变量值减1
#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) //加1之后判断是否为0,
如果 == 0 为真,1,如果不为0,为假,0
#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) //减1之后判断是否为0,
如果 == 0 为真,1,如果不为0,为假,0
static inline int atomic_add_return(int i, atomic_t *v)
{
unsigned long flags;
int val;
raw_local_irq_save(flags);
val = v->counter;
v->counter = val += i;
raw_local_irq_restore(flags);
return val;
}
--------解决什么问题啊? 举个例子(伪代码):
多个进程同时控制灯,无法达到用户预期
A : open
atomic_dec(1)
xxxxxdemo_ioctl
--------- =0
close
atomic_inc(v)
B :
if(!atomic_dec_and_test(v)){
printf("设备忙,等一等吧.\n");
atomic_inc(v)
return -EBUSY;
}
整合:
demo_open()
{
if(!atomic_dec_and_test(v)){
printf("设备忙,等一等吧.\n");
atomic_inc(v)
return -EBUSY;
}
//atomic_dec(1);
}
demo_close()
{
atomic_inc(v)
}
代码实例(之前流水灯的代码):
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <asm/atomic.h>
#define FS4412LEDON 1
#define FS4412LEDOFF 0
#define GPX2CON 0x11000C40
#define GPX2_7DAT 0x11000c44
#define GPX1CON 0x11000c20
#define GPX1DAT 0x11000c24
#define GPF3CON 0x114001e0
#define GPF3DAT 0x114001e4
void __iomem * gpx2con_vir;
void __iomem * gpx2dat_