一、并发基本概念
1.并发
并发的概念是:多个执行单元同时、并行被执行
Linux系统是多任务的,很多任务会同时执行
假如有三个执行单元ABC,共享了内存资源
执行单元A对Buffer写1000个"a";
执行单元B对Buffer写1000个"b";
执行单元C从Buffer中读取数据。
如果按照A写→C读→B写→C读,当然没有问题。
但是如果A写→B写→C读,执行单元C就出问题了。
当然比这个复杂更多,更加混乱的并发操作存在设备驱动中。
只要有多个进程对共享资源的同时访问,就可能出现竞争。
2.竞态
以下三种情况会导致竞态
对称多处理的多个CPU
单CPU内进程和强占它的进程
中断和进程
3.竞态的解决办法
解决竞态的途径是“保证对共享资源的互斥访问”
也就是一个执行单元在访问共享资源的时候,其他的执行单元被禁止访问。
访问共享资源的代码区称为临界区,临界区需要使用互斥机制来保护。
4.Linux操作系统中提供实现互斥的方法
原子操作、自旋锁、信号量、互斥体等。
后续视频介绍原子操作,自旋锁,互斥体
二、并发控制之原子操作
1.直接列出内核中提供的宏定义
解决竞态的途径是"保证对共享资源的互斥访问"
变量:atomic_t 整型变量
宏定义:atomic_read (*(volatile int *)&(v)->counter)
volatile关键词:表示变量每次被访问,执行单元每次从内存单元中取值。
不带关键词:表示变量在编译的时候可能被"优化"。(可能是CPU内部寄存器)
保证对特殊地址的稳定访问!
宏定义:atomic_inc atomic_add(1, (v)) 变量加1
宏定义:atomic_dec 变量减1
宏定义:ATOMIC_INIT 赋值
2.如何使用
假设任务单元A第一个申请"共享单元"。则先读变量,如果0,则对变量加1,然后对共享资源进行操作。操作完毕之后对变量赋值。
假设任务单元B要申请"共享单元"。则先读变量,如果0,则对变量加1,然后对共享资源进行操作。操作完毕之后对变量赋值。如果为1,直接返回。
3.代码分析
open_atomic_int_one以及open_atomic_int_two两个程序
要对/dev/atomic_int设备节点镜像操作
先运行的程序,将变量赋值为1,释放的时候赋值为0
如果程序1在没有释放的情况下,程序2调用设备节点则会直接返回,无法调用。
如果程序1在在没有释放的情况下,程序2调用则会直接返回,无法调用。
atomic
#include #include /* device register */ #include /* register misc device */ #include /* register device node */ #include /* atomic */ #include #include #define DRIVER_NAME "atomic_int" #define DEVICE_NAME "atomic_int" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Topeet"); static atomic_t value_atomic = ATOMIC_INIT(0); static int atomic_int_open(struct inode *inode, struct file *file) { printk(KERN_EMERG "atomic_int open in!n"); if(atomic_read(&value_atomic)) { return -EBUSY; } atomic_inc(&value_atomic); printk(KERN_EMERG "atomic_int open success!n"); return 0; } static int atomic_int_release(struct inode *inode, struct file *file) { printk(KERN_EMERG "atomic_int releasen"); atomic_dec(&value_atomic); return 0; } static struct file_operations atomic_int_ops = { .owner = THIS_MODULE, .open = atomic_int_open, .release = atomic_int_release, }; static struct miscdevice atomic_int_dev = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &atomic_int_ops, }; static int atomic_int_probe(struct platfrom_device *pdv) { printk(KERN_EMERG "tinitalizedn"); misc_register(&atomic_int_dev); return 0; } static int atomic_int_remove(struct platform_device *pdv) { printk(KERN_EMERG "tremvoen"); misc_deregister(&atomic_int_dev); return 0; } struct platform_driver atomic_int_driver = { .probe = atomic_int_probe, .remove = atomic_int_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, } }; static int atomic_int_init(void) { int DriverState; printk(KERN_EMERG "atomic int entern"); DriverState = platform_driver_register(&atomic_int_driver); printk(KERN_EMERG "tDriverState is %dn", DriverState); return 0; } static void atomic_int_exit(void) { printk(KERN_EMERG "atomic int exitn"); platform_driver_unregister(&atomic_int_driver); } module_init(atomic_int_init); module_exit(atomic_int_exit); open_one: #include #include #include #include #include #include int main(int argc, char *argv[]) { char *atomic_int = "/dev/atomic_int"; int fd; if((fd = open(atomic_int, O_RDWR|O_NDELAY)) < 0) { printf("%s open %s fialed!n", argv[0], atomic_int); } else { printf("%s open %s success!n", argv[0], atomic_int); } while(1); } opne_two: #include #include #include #include #include #include int main(int argc, char *argv[]) { char *atomic_int = "/dev/atomic_int"; int fd; if((fd = open(atomic_int, O_RDWR|O_NDELAY)) < 0) { printf("%s open %s fialed!n", argv[0], atomic_int); } else { printf("%s open %s success!n", argv[0], atomic_int); } while(1); } [root@iTOP-4412]# insmod atomic.ko [ 69.905118] atomic int enter [ 69.906830] initalized [ 69.925677] DriverState is 0 [root@iTOP-4412]# ls /dev/atomic_int -l crw-rw---- 1 root 0 10, 47 Jan 1 01:47 /dev/atomic_in [root@iTOP-4412]# ./open_atomic_int_one & [root@iTOP-4412]# [ 83.577155] atomic_int open in! [ 83.578851] atomic_int open success! ./open_atomic_int_one open /dev/atomic_int sucess! [root@iTOP-4412]# ./open_atomic_int_two [ 92.529032] atomic_int open in! ./open_atomic_int_two open /dev/atomic_int failed! [root@iTOP-4412]# kill 1659 [root@iTOP-4412]#[ 115.020445] atomic_int release [1]+ Terminated ./open_atomic_int_one [root@iTOP-4412]# ./open_atomic_int_two [ 120.023368] atomic_int open in! [ 120.025137] atomic_int open success! ./open_atomic_int_two open /dev/atomic_int sucess! ^C[ 123.292457] atomic_int release 遇到的问题: 一开始注册,没有运行probe函数。所以需要对内核裁剪(driver/char/Kconfig和arch/arm/mach-exynos/mach-top4412.c的修改)。 增减ATOMIC_INT_CONFIG,并编译内核后烧录。 三、并发控制之位原子操作 1.直接列出内核中提供的宏定义 宏定义:test_bit 返回位原子值 宏定义:set_bit 设置位 宏定义:clear_bit 清除位 2.如果使用 类似整型的原子操作 3.代码分析 open_atomic_bit_two以及open_atomic_bit_one两个程序 要对/dev/atomic_bit这个设备节点进行操作 先运行open之后,将变量赋值为1,释放的时候赋值为0 如果在其中一个程序调用的过程中没有释放,第二个程序要对节点操作,则会直接返回错误。 atomic_bit #include #include /* device register */ #include /* register misc device */ #include /* register device node */ #include /* atomic */ #include #include #define DRIVER_NAME "atomic_bit" #define DEVICE_NAME "atomic_bit" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Topeet"); //static atomic_t value_atomic = ATOMIC_INIT(0); unsigned long int value_bit = 0; static int atomic_bit_open(struct inode *inode, struct file *file) { printk(KERN_EMERG "atomic_int open in!n"); /* if(atomic_read(&value_atomic)) { return -EBUSY; } atomic_inc(&value_atomic); */ if(test_bit(0, &value_bit) != 0) { return -EBUSY; } set_bit(0, &value_bit); printk(KERN_EMERG "atomic_int open success!n"); return 0; } static int atomic_bit_release(struct inode *inode, struct file *file) { printk(KERN_EMERG "atomic_int releasen"); //atomic_dec(&value_atomic); clear_bit(0, &value_bit); return 0; } static struct file_operations atomic_bit_ops = { .owner = THIS_MODULE, 4.测试结果
测试代码:
上一篇:4412 RS485
下一篇:4412 GPIO读 和 ioremap控制GPIO寄存器
推荐阅读最新更新时间:2024-11-17 11:17
推荐帖子
- 十进制转换成BCD的汇编程序
- 十进制转换成BCD的汇编程序十进制转换成BCD的汇编程序路过支持一下!帮顶
- shangwlscp 嵌入式系统
- 无线模块nRF905最全资料(包括AVR,C51的测试程序)
- 无线模块nRF905最全资料,包括AVR(ATmega16),C51的测试程序。无线通信模块选型指南,无线通信计算方法无线模块nRF905最全资料(包括AVR,C51的测试程序)看看好不,正要用这个这些资料太好了,多谢分享太好了今年的无线通信模块是用到控制类上吗很好很强大的哇,楼主很犀利楼主还是感谢你两回吧,我没钱啦楼主还是感谢你两回吧,我没钱啦貌似很多人都用这个模块,会不会考虑使用ZigBee呢?大赛要用这个啊元器件清单出来了,楼主的帖子一定很受欢迎,呵呵。我也收下了
- lly200 电子竞赛
- [转]IDC年度盛典,指引中国IDC产业发展新方向
- 来源:IT资源库http://news.itdb.cn/n/200801/15/u20080115_1257.shtml中国IDC产业年度大典即将于2008年1月16日盛大开幕。这是中国IDC产业进入新年的头件大事。信产部的有关领导和业内专家将在会上全面解读2008年中国IDC行业的市场环境及监管政策,为IDC服务商的稳定发展指明方向。届时,国内外知名的电信运营商、IDC服务商、互联网增值服务商都将高度参与和关注此次盛典。回顾2007年,中国的IDC产业一直处于调整和发展之中,大多
- ll19860607 RF/无线
- H264编解码相关问题
- 我的设备是8127,H264编解码基础问题想请教一下:1、8127中的videoM3编码的输出,也就是每次ipcbitsout的输出就是一个NALU单元吗?2、我想读入本地的H264文件,然后交给videoM3解码,请问我每次应该读入多少内容呢?就一个NALU单元吗?H264编解码相关问题
- comeback DSP 与 ARM 处理器
- ULP Advisor 使用期间bug说明
- 小右派说::论坛上下载的IARMSP4305.5集成了ULPadvisor,具体解释ULPadvisor就是ultralowpoweradvisor,即使这个ULP.exe程序会对你的代码检查,给你提供省电的建议。小右派说::看图1,IAR中的ULPadvisor,对准工程名称,右键,选择option,找到Tiulpadvsor,选中enable框,这样就可以对你的代码进行检查,给出优化提示。对于我很有帮助。小右派说::执行complies,make,给出如图的提
- 小右派 微控制器 MCU
- 【英飞凌XENSIV™ PAS CO2传感器】CO2标气测试
- CO2标气测试肆虐的口罩终于算是有了一个阶段了,终于让我拿到了CO2的标气,根据英飞凌CO2传感器的显示范围,选取的是25000PPM(2.5%)的标气,填充气为氮气。一直在思索如何测试能减少干扰呢?压力会对结果产生影响,所以不能用流动的气体吹;完全封闭的盒子还不太好实现,还需要透明可以看到示数;透明的袋子呢,这个相对比较好实现一点。找来一个比较大的透明袋子,严密性良好,将测试设备放入其中,尽可能的排出空气(没有抽气设
- 秦天qintian0303 传感器
设计资源 培训 开发板 精华推荐
- SPC560B64A208S,用于 QFP144 封装的 SPC560 系列 512KB/1.5MB 器件的子板/适配器板
- 通讯人机交互扩展板+828006A
- KITFS26SKTEVM: FS26安全SBC编程插座板
- 电磁炮工程
- 使用 Analog Devices 的 LTC1148 的参考设计
- 用于 LCD 偏置发生器的 LT1307IS8 PWM 转换器的典型应用电路
- LM2902VDTBR2G高阻差分放大器典型应用
- LTM8054IY 2 同步和开关降压-升压转换器 LTM8054 的典型应用电路由具有不同电流能力的输入源供电共享输出电流以运行单个负载
- LT1021DCS8-7 用于处理更高负载电流的电压基准的典型应用
- NCP3337MN330GEVB:3.3 V LDO 稳压器评估板