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

发布者:shiwanyongbing最新更新时间:2016-06-06 来源: eefocus关键字:arm驱动  linux并发  竞态并发控制 手机看文章 扫描二维码
随时随地手机看文章
《[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

a)声明一个spinlock_t 变量lock

spinlock_t lock;

b)初始化spinlock_t 变量lock

有两种初始化方式:宏初始化与函数初始化

1)宏初始化方法SPIN_LOCK_UNLOCKED

spinlock_t lock = SPIN_LOCK_UNLOCKED;

2)函数初始化方法spin_lock_init(lock)

spin_lock_init(lock)

内核源码五)spin_lock_init的内核源码

//内核源码spin_lock_init发现使用SPIN_LOCK_UNLOCKED
#define spin_lock_init(lock) do{ *(lock) = SPIN_LOCK_UNLOCKED; } while(0)

c)获得自旋锁

1、获得自旋锁,spin_lock(lock) ;如果成功,立即获得锁,并马上返回,否则它将一直自旋在那里,直到该自旋锁的保持者释放。

spin_lock(lock)
//获取自旋锁lock,如果成功,立即获得锁,并马上返回,否则它将一直自旋在那里,直到该自旋锁的保持者释放。

内核源码六) spin_lock(lock)内核源码分析

//源码内核(可以看出来spin_lock没有获取锁,它将一直做while循环)
spin_lock(lock) _spin_lock(lock)
#define _spin_lock(lock) __LOCK(lock)
#define __LOCK(lock) do{ preempt_disable(); __acquire(lock); (void)(lock); } while(0)
#define preempt_disable() do{ } while(0)
//preempt_disable做空循环

2、试图获取自旋锁函数的spin_trylock(lock),如果能立即获得锁,并返回真,否则立即返回假。它不会一直等待被释放。(spin_trylock(lock)不做忙等待)
d)释放自旋锁lock,函数spin_unlock(lock) 它与spin_trylock或spin_lock配对使用。

3、自旋锁spinlock使用模板

模板四)自玄锁模板

spinlock_t lock;
spin_lock_init(&lock);
spin_lock(&lock);
spin_unlock(&lock);

Tip:将要保护的值(全局变量,静态变量,硬件资源)放在spin_lock(&lock)与spin_unlock(&lock)之间操作

spin_lock(&lock);
//改变要保护的全局变量或硬件资源或静态变量(共享变量)
spin_unlock(&lock);

4、特殊使用场景:有些设备只允许被打开一次,那么就需要一个自旋锁保护表示设备的打开和关闭状态的变量count。此处count属于临界资源,如果不对count进行保护,当设备打开频繁时,可能出现错误的count计数。

模板五)只允许被打开一次的设备驱动模板

intcount = 0;
spinlock_t lock;
intxxx_init(void){
//...其他代码..
spin_lock_init(&lock);
//...其他代码..
}
intxxx_open(structinode *inode, structfile *file){
spin_lock(&lock);//如果相同程序的进程要用open,那么其他进程就进入忙等到while(1)
if(count){
spin_unlock(&lock);
return-EBUSY;
}
count++;
spin_unlock(&lock);
//.....
}
intxxx_release(structinode *inode, structfile *file){
//....
spin_lock(&lock);//关闭时也要进行spin_lock保护,因为count是全局变量,要改变count就要加自旋锁
count--;
spin_unlock(&lock);
//.....
}

Tip:linux自旋锁和信号量所采用的"加锁(down)---访问临界区(critical section)---释放锁"的方式,被称为"互斥三部曲"。

五、总结:编写对共享资源(硬件资源和软件上的全局变量,静态变量等)的访问的驱动程序场景,就要考虑避免竞态的发生;避免方法:信号量(或说旗标,semaphore)机制与spin_lock机制(自旋锁)。

六、补充:信号量与自旋锁对比
信号量可能允许有多个持有者,而自旋锁在任何时候只能允许一个持有者。当然也有信号量叫互斥信号量(只能一个持有者),允许有多个持有者的信号量叫计数信号量。
信号量适合于保持时间较长的情况;而自旋锁适合于保持时间非常短的情况,在实际应用中自旋锁控制的代码只有几行,而持有自旋锁的时间也一般不会超过两次上下文切换的时间,因为线程一旦要进行切换,就至少花费切出切入两次,自旋锁的占用时间如果远远长于两次上下文切换,我们就应该选择信号量。

关键字:arm驱动  linux并发  竞态并发控制 引用地址:arm驱动linux并发与竞态并发控制

上一篇:arm驱动linux异步通知与异步IO
下一篇:arm驱动linux并发与竞态---并发控制

推荐阅读最新更新时间:2024-03-16 14:56

arm驱动linux等待队列阻塞中断IO的应用
《 linux等待队列阻塞中断IO的应用》涉及内核驱动函数四个,内核结构体零个,分析了内核驱动函数四个;可参考的相关应用程序模板或内核驱动模板一个,可参考的相关应用程序模板或内核驱动一个 一、概念: 要休眠进程,必须有一个前提:有人能唤醒进程,而起这个人必须知道在哪儿能唤醒进程,这里,就引入了 等待队列 这个概念。 二、应用场景: 等待队列用来实现进程的阻塞,等待队列可看作保存进程的容器,在阻塞进程时,将进程放入等待队列,当唤醒进程时,从等待等列中取出进程。进程进入休眠后必须有个地方能够唤醒休眠的进程;唤醒进程的地方最大可能是中断里面,应为硬件资源的获取的同时往往伴随着一个中断。所以在中断中常常使用等待队列来休眠进程,将cpu资源让
[单片机]
ARM9+Linux下电子纸驱动的设计与实现
为实现在ARM9+Linux系统下对电子纸的快速、有效控制,设计了一种基于电子纸显示控制芯片(GD6210E)的电子纸驱动。根据S3C2440 ARM9处理器和GD6210E的接口特点,利用S3C2440的GPIO口来扩展GD6210E,最后利用Linux为显示设备提供的帧缓冲专用接口编写驱动程序,完成电子纸的驱动。该驱动有利于电子纸的普及应用。 电子纸可以实现显示内容的重写,具有对比度高、重量轻、可以适当弯曲,且在断电的情况下,能保持原有的显示内容等优点。Linux是一种具有开放性、多用户、多任务、设备独立性、系统可靠安全、良好移植性等优点的操作系统 ,其内核可根据具体的运行平台进行适当的裁剪,这对于资源有限的嵌入式系统至关重
[单片机]
<font color='red'>ARM</font>9+<font color='red'>Linux</font>下电子纸<font color='red'>驱动</font>的设计与实现
ARM笔记: SDRAM内存驱动
SDRAM(Synchronous Dynamic Random Access Memory,同步动态随机存储器)也就是通常所说的内存。内存的工作原理、控制时序、及相关控制器的配置方法一直是嵌入式系统学习、开发过程中的一个难点。我们从其硬件的角度来分析其原理,然后再引出SDRAM的驱动编写过程。 内存是代码的执行空间,以PC机为例,程序是以文件的形式保存在硬盘里面的,程序在运行之前先由操作系统装载入内存中,由于内存是RAM(随机访问存储器),可以通过地址去定位一个字节的数据,CPU在执行程序时将PC的值设置为程序在内存中的开始地址, CPU会依次的从内存里取址,译码,执行,在内存没有被初始化之前,内存好比是未建好的房子,是不能读取
[单片机]
<font color='red'>ARM</font>笔记: SDRAM内存<font color='red'>驱动</font>
基于ARM的无线网卡设备驱动方案
  随着嵌入式系统中无线局域网的接入,既可以实现对嵌人式系统的无线控制和数据传输,又可以满足一些特殊应用的场合。这里通过对USB无线网卡的Linux设备驱动的深入理解和分析,成功地移植在Atmel 9261 ARM处理器上。实现了嵌入式系统的无线局域网接入。利用该平台,可以进一步设计完善医用伽马相机和小型SPECT设备的手持数据采集系统,使得控制人员能够远离数据采集现场,而通过远程终端来控制现场数据和各种控制信号,较好地解决了安全性问题。   1 硬件系统构成   1.1 USB无线网卡介绍   无线网卡是无线局域网(WLAN)的重要组成部分,WLAN的物理层及MAC层是用无线网卡的硬件及其软件完成的,而LLC层以上各层均由计
[单片机]
基于<font color='red'>ARM</font>的无线网卡设备<font color='red'>驱动</font>方案
基于ARM含SD控制器的SD卡的SDIO模式驱动解析
SD卡由日本 松下 、 东芝 及美国 SanDisk 公司于1999年8月共同开发研制。 SD卡的结构能保证数字文件传送的安全性,也很容易重新格式化,因此越来越多的被应用的嵌入式系统中。 SD卡的使用非常方便,常见的有两种工作模式:SPI和SDIO。SPI是串行的工作模式,速度相对较低,但是使用方便,只要MCU含有SPI接口均可使用。SDIO模式,可以最多4线传输,因此速度比较快,由于SD卡的普及,越来越多的MCU内部集成了SDIO控制器,简化了我们的工作。本文以三星s3c2410为例介绍。 1. SD卡的接口电路 2. SD卡的协议 SD卡的控制指令非常强大,支持SPI,SDIO模式,兼容MMC等。而且
[单片机]
基于<font color='red'>ARM</font>含SD<font color='red'>控制</font>器的SD卡的SDIO模式<font color='red'>驱动</font>解析
ARM-Linux驱动相关头文件知识点
#include linux/***.h 在linux-2.6.31/include/linux下面寻找源文件 #include asm/***.h 在linux-2.6.31/arch/arm/include/asm下面寻找源文件 #include mach/***.h 在linux-2.6.31/arch/arm/mach-s3c2410/include/mach下面寻找源文件 #include plat/regs-adc.h 在linux-2.6.31/arch/arm/plat-s3c/include/plat下面寻找源文件 ---------------------------------------------
[单片机]
ARM-Linux驱动移植--Linux下烧写工具DNW和USB驱动安装
主机平台:Gentoo Linux 11.2 with linux kernel 3.0.6 硬件平台:FL2440(S3C2440)with linux kernel 2.6.35 原创作品,转载请标明出处 http://blog.csdn.net/yming0221/article/details/7211396 1、首先下载DNW for linux http://download.csdn.net/source/1011140 2、解压文件 、 3、编译主机的USB驱动 make -C /lib/modules/`uname -r`/build M=`pwd` modules 然后insmod
[单片机]
<font color='red'>ARM</font>-<font color='red'>Linux</font><font color='red'>驱动</font>移植--<font color='red'>Linux</font>下烧写工具DNW和USB<font color='red'>驱动</font>安装
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved