产生的原因:Linux是一个多任务操作系统,肯定会存在多个任务共同操作同一段内存或者设备的情况,对于多个任务甚至中断都能访问的资源(共享资源)需要保护。也就是要处理对共享资源的并发访问
同时访问某个数据:同时就是并发 他们之间存在着竞争关系
并发的原因:多任务系统,中断,抢占,多核,线程 等竞争资源他们之间存在竞争关系
如何处理:即在他们可以共同访问的数据段中保证一次只要一个线程访问 即原子访问(这么称呼是因为原子是一个整体 不拆分)
保护的是:数据 是多个线程都会访问的共享数据(可以是全局变量)
——————————————————————————————
本案例使用原子操作 ---一次只允许一个应用程序可以使用 LED 灯。
使用的对象:变量或者位--------linux系统提供了一系列的API函数
——————————————————
/*gpioled设备结构体*/
/*该设备需要的*/
struct gpioled_dev
{
dev_t devid; /*设备号 32位*/
int major ;/*主设备号 高12位*/
int minor ;/*次设备号 低20位*/
/*cdev表示字符设备 结构体初始化就是初始化结构体变量*/
struct cdev cdev ;//包含了操作函数集 和 设备号 包含头文件 #include <linux/cdev.h>
struct class *class; /*类*/
struct device *device; /*设备*/
struct device_node *nd; //节点
int led_gpio ;//led 所使用的 GPIO 编号
atomic_t lock;//添加原子 变量 (第一步:使用原子变量代替整形变量)
};
struct gpioled_dev gpioled;
————————————————————————————————————————
/*入口 -注册字符设备*/中注册设备号 /cdev 具体的字符设备操作集合 向内核添加字符设备 自动创建设备节点 不变
在驱动入口函数中:
1、 /*定义原子变量的时候对其初始化*/
atomic_set(&gpioled.lock, 1);
———————————————————————————
在操作函数集中
static struct file_operations gpioled_fops =
{
.owner = THIS_MODULE ,
.open = gpioled_open,
.write = gpioled_write,
.release = gpioled_release,
};
————————————
法1
static int gpioled_open(struct inode *inode, struct file *filp){
//私有数据
filp->private_data = &gpioled ;
/*第一次打开应用程序的时候需要进行判断 原子变量lock*/
//atomic_read读取原子变量的值 并且返回
if( atomic_read(&gpioled.lock) <= 0 ) { /*说明应用程序已经使用过一次 程序不可运行*/
return -EBUSY;
}else{ /*说明可以用 但是需要减去1 因为驱动刚加载的时候为原子变量初始化为1*/
atomic_dec(&gpioled.lock); //原子变量自减的API函数 =0
//达到了应用程序只是执行一次的目的
}
return 0;
}
法2
static int gpioled_open(struct inode *inode, struct file *filp)
{
//私有数据
filp->private_data = &gpioled ;
/*第一次打开的时候需要进行判断 原子变量lock*/
//使用一个函数 从 v 减 1,如果结果为 0 就返回真,否则返回假
//atomic_dec_and_test 减 1,如果结果为 0 就返回真,否则返回假
if( !atomic_dec_and_test(&gpioled.lock) ){
//第一次执行的时候 一开始是1 减去1 为0 返回真 取反 不执行
//此时如果再次执行 0-1=-1 执行
//不为0 代表无效 无效之后需要处理 加1 ==由-1变成0、
atomic_inc(&gpioled.lock);//自增
return -EBUSY;
}
return 0;
}
——————————————————————
static int gpioled_release(struct inode *inode, struct file *filp)
{
//可以通过私有数据访问struct gpioled_dev gpioled
struct gpioled_dev *dev = (struct gpioled_dev*)filp->private_data;
/*释放的时候需要给automic变量加回去*/
atomic_inc(&dev->lock);//1
return 0;
}
——————其余API函数不变