博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OK6410A 开发板 (八) 66 linux-5.11 OK6410A linux 并发 竞态 与 同步
阅读量:4285 次
发布时间:2019-05-27

本文共 4007 字,大约阅读时间需要 13 分钟。

并发执行单元引起的错误 : 竞态案例

a 初始化 为 0A 内核进程 对 变量 a 加1B 内核进程 对 变量 a 加1a 现在 为 2下面的顺序不会有问题A load 	内存中的a 进 寄存器A 寄存器 	自加 1A store 	寄存器中的值 进 内存B load 	内存中的a 进 寄存器B 寄存器 	自加 1B store 	寄存器中的值 进 内存此时a的值为2下面的顺序会有问题A load 	内存中的a 进 寄存器1A 寄存器1 	自加 1B load 	内存中的a 进 寄存器2B 寄存器2 	自加 1A store 	寄存器1中的值 进 内存B store 	寄存器2中的值 进 内存此时a的值为1 // 此时发生了竞态 : 意想不到的事件// 此时 a 被 两个内核线程访问,a叫做共享资源// 此时 "A 内核进程 对 变量 a 加1" 这个动作相关的代码叫做临界区

内核态并发原因分类

-----------------------------------------竞态由于 中断 调度 	的存在, 会存在 伪并发由于 SMP 		的存在, 会存在 真并发解决 中断 矛盾问题引入了软中断,也就引入了 软中断 产生的竞态在 __irq_svc 返回时调度, 也就引入了内核抢占的 竞态总之, 竞态原因有以下五种	中断	调度	SMP	软中断	内核抢占对于内核代码(驱动,内核线程,中断,其他内核模块)来说(因为地址空间相同),存在的并发原因有五种	中断	调度	SMP	软中断	内核抢占
  • 非SMP的内核态并发路径
中断处理程序可以打断软中断,tasklet和进程上下文的执行软中断和tasklet之间不会并发,但可以打断进程上下文的执行在支持抢占的内核中,进程上下文之间会产生并发在不支持抢占的内核中,进程上下文之间不会产生并发
  • SMP的内核态并发路径
同一类型的中断处理程序不会并发,但是不同类型的中断有可能被送到不同的cpu上,因此不同类型的中断处理程序可能存在并发执行同一类型的软中断会在不同的cpu上并发执行同一类型的tasklet是串行执行的,不会再多个cpu上并发不同cpu上的进程上下文会并发
  • 内核态哪些资源需要保护
静态局部变量全局变量共享的数据结构缓存链表红黑树

用户态并发原因分类

对于应用代码来说,存在的并发原因有一种(对 进程地址空间中的内存相同部分 进行并发访问),这时候我们不对 并发原因(并发原因只有调度)分类,而是对(共享资源)分类,共享资源分为多种	多线程代码中的所有变量	多进程代码中的共享内存中的变量

解决竞态的方案

  • 同步的概念
解决竞态的方案 叫做 同步所有的 同步 都是基于原子操作,是芯片提供的指令,不是软件做的.软件做的是在原子操作的封装同步根据 竞态原因 的不同, 而 分为多种
  • 所有同步机制都存在的问题 - 乱序
// 涉及同步时,指令重排可能会带来问题,如果放在同步原语之后的指令在同步原语之前被执行了,就可能会出问题我们可以用不同的 同步 方法 围住 共享资源 保证 在 某个情景下 不会产生竞态虽然在代码上,我们的同步方法围住了共享资源, 但是 却 不能保证 共享资源 一定会被 同步 方法 围住.因为存在着cpu重排序指令这个问题这个问题主要分为以下几种: // https://blog.csdn.net/Roland_Sun/article/details/106895899	1.编译器编译时的优化	2.处理器执行时的多发射和乱序优化	3.读取和存储指令的优化	4.缓存同步顺序(导致可见性问题)而cpu 重排序指令的 解决方案 为 内存屏障原语,在外表现为多种形式	1. volatile 关键字 // 被volatile修饰的变量在编译成字节码文件时会多个lock指令,该指令在执行过程中会生成相应的内存屏障,以此来解决可见性跟重排序的问题	2. barrier() // 解决编译器乱序	3. mb/rmb/wmb/smp_mb/smp_rmb/smp_wmb // 解决运行时乱序volatile 关键字使用的是Lock指令,volatile的作用取决于Lock指令。 	// ??? TODO volatile  的实现 	// volatile 与 屏障 的区别	Lock是软件指令	Lock前缀,Lock不是一种内存屏障,但是它能完成类似内存屏障的功能。Lock会对CPU总线和高速缓存加锁,可以理解为CPU指令级的一种锁。类似于Lock指令。	volatile的变量在进行写操作时,会在前面加上lock质量前缀。	Lock前缀,Lock不是一种内存屏障,但是它能完成类似内存屏障的功能。Lock会对CPU总线和高速缓存加锁,可以理解为CPU指令级的一种锁。	而Lock前缀是这样实现的		它先对总线/缓存加锁,然后执行后面的指令,最后释放锁后会把高速缓存中的脏数据全部刷新回主内存。		在Lock锁住总线的时候,其他CPU的读写请求都会被阻塞,直到锁释放。Lock后的写操作会让其他CPU相关的cache失效,从而从新从内存加载最新的数据,这个是通过缓存一致性协议做的。 	lock前缀指令相当于一个内存屏障(也称内存栅栏)(既不是Lock中使用了内存屏障,也不是内存屏障使用了Lock指令),内存屏障主要提供3个功能:		确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;		强制将对缓存的修改操作立即写入主存,利用缓存一致性机制,并且缓存一致性机制会阻止同时修改由两个以上CPU缓存的内存区域数据;		如果是写操作,它会导致其他CPU中对应的缓存行无效。内存屏障是CPU指令
  • 所有同步机制的基础 - 同步原语(Synchronization primitives)
swap and swap byte instructions  在ARMv6中不推荐使用,建议所有软件都迁移到使用新的同步原语ARMv6提供了一种新的机制来支持更全面的非阻塞共享内存同步原语,这种原语可以扩展到多处理器系统设计中	Load-Exclusive 	: LDREX	Store-Exclusive : STREX
  • 不同的同步机制
不同的同步机制 都是 以 同步原语(Synchronization primitives) 和 屏障 为基础的针对不同的 竞态原因,有不同的同步方法	//	也就是说,如果你要怕因为中断产生竞态,那么就关中断	//  但是该技术(关中断)不会解决 其他竞态原因 产生的竞态	per-cpu 变量	atomic bit 64位 变量	禁中断/中断屏蔽	禁抢占	禁软中断	自旋锁	读写锁	顺序锁	信号量(count初始化为1)/读写信号量	互斥锁	RCU	大内核锁BLK

其他易混淆的概念

  • 解决竞态的方案(同步)与事件同步的区别
解决竞态的方案(同步) 是 为了 不让 并发(真并发和伪并发),保证数据的一致性而 事件同步 是为了 两个事件必须有先后顺序(叫做两个同步事件)不相干的事件 不需要 有先后顺序而 不管 两个事件(A B)要不要先后顺序,都需要 做 解决竞态的方案(同步) // 并发可能是 A与C B与C 的并发设计 让 两个事件同步 的 机制 有	1. 等待一段时间			// sleep	2. 等待事件完成或条件满足 // 信号量(count初始化为0) 和 等待队列 和 completion
  • 事件的同步和事件的异步
// 其实 异步事件 的使用场景 和 同步事件 的 使用场景 没有任何关系 ,没有可比性// 这里 只是 其分类为 同步和异步事件同步,某事件等待另一件事件结束事件异步,某事件不等待另一事件结束A 等待 B 结束	1. A 等待一段时间(sleep并调出) 等到 硬件复位(B)							// sleep	2. A 调用 poll(wait并调出) 等待事件完成或条件满足(数据到来)(B)   			// 等待队列A 不等待 B 结束	1. A 调用 提交任务给 tasklet/工作队列 ,A 继续执行 . B在一个时机处理 任务	// tasklet/软中断/工作队列	2. A 调用 设置回调 给 timer/hrtimer  ,A 继续执行 . 定时器到了,B调用回调 	// 定时器timer/定时器hrtimer
  • 异常的 同步 和 异步
同步 : 确定会会断在哪条指令上异步 : 不确定会会断在哪条指令上
  • IO 的同步和异步
进程A的一个IO请求分为两个过程	1.等待数据准备就绪	2.将数据从内核态拷贝到用户空间阻塞IO与非阻塞IO的定义 	第一个过程阻塞/非阻塞(A)对应 阻塞IO/非阻塞IO(B)同步IO与异步IO的定义	第二个过程阻塞/非阻塞(A)对应 同步IO/异步IO(非同步)read 非阻塞	第一个过程 阻塞	第二个过程 阻塞	第一个过程使用的 api read 不阻塞(此时说的是read的等待数据准备好)	第二个过程使用的 api read 阻塞(此时说的是read的拷贝数据)read 阻塞	第一个过程 阻塞	第二个过程 阻塞	第一个过程使用的 api read 阻塞(此时说的是read的等待数据准备好)	第二个过程使用的 api read 阻塞(此时说的是read的拷贝数据)select	第一个过程 阻塞	第二个过程 阻塞	第一个过程使用的 api select 阻塞(此时说的是select的等待数据准备好)	第二个过程使用的 api read 	阻塞(此时说的是read的拷贝数据,不是read的等待数据准备好)
你可能感兴趣的文章
响应式下的下拉菜单
查看>>
DOM笔记(九):引用类型、基本包装类型和单体内置对象
查看>>
也谈学习
查看>>
DOM笔记(十):JavaScript正则表达式
查看>>
如何高效编写可维护代码?
查看>>
DOM笔记(十一):JavaScript对象的基本认识和创建
查看>>
DOM笔记(十二):又谈原型对象
查看>>
DOM笔记(十三):JavaScript的继承方式
查看>>
CSS:响应式下的折叠菜单(条纹式)
查看>>
响应式设计三部曲
查看>>
45种Javascript技巧大全
查看>>
PDO学习笔记
查看>>
MarkDown语法
查看>>
Linux的文件权限
查看>>
全屏滚动实现:fullPage.js和fullPage
查看>>
SASS小结
查看>>
一个js闭包问题的解答
查看>>
Responsive Design常用的媒体查询
查看>>
45个必备的JavaScript Web开发工具
查看>>
CSS3实现酷炫导航
查看>>