微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > arm驱动linux并发与竞态---并发控制

arm驱动linux并发与竞态---并发控制

时间:11-19 来源:互联网 点击:
《[arm驱动]linux并发与竞态---并发控制》涉及内核驱动函数五个,内核结构体一个,分析了内核驱动函数六个;可参考的相关应用程序模板或内核驱动模板五个,可参考的相关应用程序模板或内核驱动零个

一、并发与竞态

1、并发:多个执行单元同时被执行。例如:同一个test.out可执行程序被n次同时运行
2、竞态:并发的执行单元对共享资源(硬件资源和软件上的全局变量,静态变量等)的访问导致的竞争。
a)静态的列子:

char *p;//全局变量 //    读取函数 module_drv_read(struct file *file, constchar __user *buf, size_t count, loff_t * ppos) {copy_to_user(buf, p, countt);} //写入函数 module_drv_write(struct file *file, constchar __user *buf, size_t count, loff_t * ppos) {copy_from_user(p, buf, countt)}

如果有两个进程同时在运行,一个执行read,一个执行write,那么执行read的可能会读取到第二个程序的写入值或只读取到第二个程序部分写入值。
二、如何避免竞态:(有共享就有可能发生竞争)
方法:处理竞态的常用技术是加锁或者互斥,对应semaphore(旗标)机制、spin_lock机制
三、信号量(semaphore)机制

1、旗标(信号量)

旗标(信号量):是一个整型值,结合一对函数void down(struct semaphore * sem)、void up(struct semaphore *sem),如果旗标的值大于0,这个值将减一并且继续进程。相反,如果旗标的值是0(或者更小),此进程必须等待别的进程释放旗标,解锁旗标通过调用up完成,up函数会增加旗标的值。
Tip:Linux内核的信号量在概念和原理上与用户态的信号量是一样的,但它不能在内核之外使用

2、信号量机制编程

a)信号的声明初始化有两种方式:方式1宏定义并初始化;方式2动态初始化

信号的声明初始化方式1)宏定义并初始化信号量的快捷方式

DECLARE_MUTEX(name) DECLARE_MUTEX_LOCKED(name)

内核代码1)DECLARE_MUTEX和DECLARE_MUTEX_LOCKED他们的内核代码为

#define DECLARE_MUTEX(name)        __DECLARE_SEMAPHORE_GENERIC(name, 1) #define DECLARE_MUTEX_LOCKED(name)    __DECLARE_SEMAPHORE_GENERIC(name, 0) //__DECLARE_SEMAPHORE_GENERIC的内核代码 #define __DECLARE_SEMAPHORE_GENERIC(name,count)     structsemaphore name = __SEMAPHORE_INITIALIZER (name,count)

模板一)宏定义初始化方式信号量模板

DECLARE_MUTEX(name);//定义信号量 down(&name);//加锁,保护临界区在释放锁前,将访问本临界区的进程加入等待队列中 //....要修改全局变量在这修改..... up(&name)//释放锁

信号的声明初始化方式2)动态初始化方式

1、定义信号量结构体 struct semaphore sem;

structsemaphore sem;

结构体一)struct semaphore内核源码

struct semaphore { atomic_t count;//旗号数值 intsleepers; wait_queue_head_t wait;//等待队列 };

2、初始化结构体struct semaphore sem有两种方式,宏定义初始化与函数初始化

初始化结构体sem方式a)用函数sema_init (struct semaphore *sem, int val)初始化结构体struct semaphore sem。

内核源码二)sema_init内核原型代码

static inline void sema_init (structsemaphore *sem, intval) { atomic_set(&sem->count, val); init_waitqueue_head(&sem->wait); //如果进程调用down时,发现信号量为0时就将进程加入到sem->wait等待队列中 }

模板二)sema_init初始化模板

struct semaphore sem; sema_init (&sem, 1);一开始就将旗标置1 down(&sem); up(&sem);

初始化结构体sem方式b)宏初始化,分为将sem的旗标直接初始化为1和0的两种宏初始化方法

1)init_MUTEX (struct semaphore *sem)将semaphore的旗标初始化为1

内核源码三)init_MUTEX内核原型代码

staticinline voidinit_MUTEX (struct semaphore *sem) { sema_init(sem, 1);//可以看出调用了上面的sema_init函数 // 该函数用于初始化一个互斥锁,即它把信号量sem的值设置为1 }

2)init_MUTEX_LOCKED (struct semaphore *sem)将semaphore的旗标初始化为0

内核源码四)init_MUTEX_LOCKED内核原型代码

staticinlinevoidinit_MUTEX_LOCKED (structsemaphore *sem) { sema_init(sem, 0); //该函数也用于初始化一个互斥锁,但它把信号量sem的值设置为0,即一开始就处在已锁状态。 }

模板三)宏初始化模板变量sem

struct semaphore sem; init_MUTEX(&sem);一开始就将旗标置1 down(&sem); up(&sem);

四、自旋锁
1、 概念:自旋锁最多只能被一个可执行单元持有。自旋锁不会引起调用者睡眠,如果一个执行线程试图获得一个已经被持有的自旋锁,那么这个线程就会一直进行忙循环,一直等待下去,在那里看是否该自旋锁的保持者已经释放了锁,“自旋”就是这个意思
2、自旋锁的编程步骤a,b,c,d

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top