当前位置: 首页 > news >正文

湘潭网站建设磐石网络diy网站开发公司

湘潭网站建设磐石网络,diy网站开发公司,网站开发实现软硬件环境,html如何做网站关键词 原子操作、自旋锁、信号量、mutex、读写锁、percpu-rwsem 概述 从浅到深#xff0c;逐步分析各种同步机制的功能。 1、原子操作 解决“读-修改-回写”的完整性#xff0c;一般用于静态全局变量的保护#xff0c;静态全局变量的操作过程. 例如#xff0c;我们写一… 关键词 原子操作、自旋锁、信号量、mutex、读写锁、percpu-rwsem 概述   从浅到深逐步分析各种同步机制的功能。 1、原子操作   解决“读-修改-回写”的完整性一般用于静态全局变量的保护静态全局变量的操作过程. 例如我们写一行代码把变量a加1编译器把代码编译成3条汇编指令。 1把变量a从内存加载到寄存器。 2把寄存器的值加1。 3把寄存器的值写回内存。 由于是三条指令无法保障三条指令中间不会被抢占。通过一个实际的案例场景来帮助理解。     在上面的执行场景进程2对a1的结果被进程1覆盖了最终看到的结果是a仅被1我们期望a被2。 1.1.1常用原子操作函数   函数原型语义atomic_read(v)读取原子变量v的值atomic_add_return(i, v)把原子变量v的值加上i并且返回新值atomic_add(i, v)把原子变量v的值加上iatomic_inc(v)把原子变量v的值加上1int atomic_add_unless(atomic_t *v, int a, int u);如果原子变量v的值不是u那么把原子变量v的值加上a并且返回1否则返回0atomic_inc_not_zero(v)        如果原子变量v的值不是0那么把原子变量v的值加上1并且返回1否则返回0。atomic_sub_return(i, v)把原子变量v的值减去i并且返回新值atomic_sub(i, v)把原子变量v的值减去iatomic_dec(v)把原子变量v的值减去1atomic_cmpxchg(v, old, new)执行原子比较交换如果原子变量v的值等于old那么把原子变量v的值设置为new。返回值总是原子变量v的旧值{}_relaxed不内嵌内存屏障原语{}_acquire内置了加载-获取内存屏障园原语{}_release内置了存储-释放内存屏障原语 在这些基础原子操作函数上又进行了一些演进得到了很多的原子操作函数。所有的原子操作函数可以直接查看atomic-fallback.h 2、经典自旋锁   2.1原理介绍   自旋锁用于处理器之间的互斥适合保护很短的临界区并且不允许在临界区睡眠。申请自旋锁的时候如果自旋锁被其他处理器占有本处理器自旋等待也称为忙等待。     进程、软中断和硬中断都可以使用自旋锁。 目前内核的自旋锁是排队自旋锁queued spinlock也称为“FIFO ticket spinlock”算法类似于银行柜台的排队叫号。 1锁拥有排队号和服务号服务号是当前占有锁的进程的排队号。 2每个进程申请锁的时候首先申请一个排队号然后轮询锁的服务号是否等于自己的排队号如果等于表示自己占有锁可以进入临界区否则继续轮询。 3当进程释放锁时把服务号加1下一个进程看到服务号等于自己的排队号退出自旋进入临界区。 2.2代码实现   2.2.1关键数据结构   数据结构中除了owner是指针变量其他都是实体变量也就是说spinlock 结构体定义一个spinlock变量那么结构体里的变量都会被实例化。 2.2.2关键函数接口     2.2.2.1spin_lock_init   如果没有开debug宏初始化函数仅对raw_lock初始化为0 2.2.2.2spin_lock   spin_lock() - raw_spin_lock() - _raw_spin_lock() - __raw_spin_lock()  - do_raw_spin_lock() - arch_spin_lock()     代码实现很简单lock-slock先读一份保存在本地lockval然后lock-slock的next位域1然后在while循环中判断owner域是否等于本地记录的next域如果相等就表示拿锁成功。 2.2.2.3spin_unlock   spin_unlock-__raw_spin_unlock-do_raw_spin_unlock-arch_ spin_unlock 释放锁的逻辑也非常简单直接对ower位域1.     2.3稳定性维测能力介绍   假设某个thread拿了spinlock后长时间不释放引发了稳定性问题如何来定位具体是哪个线程拿了锁。可以通过CONFIG_DEBUG_SPINLOCK开关打开持锁的owner跟踪。 2.4应用场景    保护执行路径短且快。 2.5思考   2.5.1开CONFIG_DEBUG_SPINLOCK是否会引入性能问题   Debug的原理就是增加了一个owner指针变量来记录拿锁的task对owner的操作仅是简单的赋值因此对性能的影响可以忽略不计。     2.5.2raw_spinlock与spinlock的区别   在arm64上两个函数完全等价。 3、信号量   3.1原理介绍   锁创建时通过count钥匙数量值定义了最多可以有多少条路径同时访问临界区。假设初始时count值初始化为n制造n把进入临界区的钥匙那么允许有n个thread同时获得锁n把钥匙都用完了还有想申请钥匙的线程就只能放到等待队列中了。 这个机制没有定义进入临界区的线程的具体行为readwrite如果拿到钥匙的线程都写临界区的数据那么临界区最终的数据是不可预测的。这也就导致了这个机制无法推广使用不是不用实在没法用。一些铁杆粉丝非要使用它那么只能将count值初始化为1当互斥信号量使用。 为了对后续其他锁理解简要说明信号量机制关键数据结构与关键函数接口。 3.2代码实现   3.2.1关键数据结构     3.2.2关键函数接口   3.2.2.1semaphore 的初始化   主要完成struct semaphore的3个变量初始化DEFINE_SEMAPHORE初始化宏给count值默认为1. 3.2.2.2down       实现逻辑比较简单count 0就可以快速拿到锁如果count 0就走慢速路径__down慢路径里可能会睡眠。慢速路径不再做详细分析。 3.2.2.3up   释放锁对count如果wait_list不为null唤醒第一个waiter。 3.3应用场景   不推荐使用。 3.4思考   Count是个全局变量多个CPU可能并行操作可能造成致命的同步问题。如果出现死锁造成稳定性问题无法根据问题现场定位出问题根因。     4、互斥锁-mutex   4.1原理介绍   主要实现资源的互斥操作确保在一个时刻只有一个线程可以操作临界资源。 Mutex在变量owner上做较多文章。通过判断owner是0与非0来区分 锁是否空闲状态。当有线程进入临界区获得锁将该线程的task赋值给owner方便定位死锁问题。通过flag标记位实现乐观自旋与handoff机制。 为了快速理解代码的实现下面用问答的形式来帮助深度理解锁的实现原理。 4.1.1互斥锁与互斥信号量原理类似为什么还要实现互斥锁   互斥锁相对互斥信号量要轻便一些数据结构比信号量小执行速度比信号量快加入了乐观自旋等待机制。 互斥锁最先实现自旋等待互斥锁在睡眠之前会尝试获取锁互斥锁通过实现MCS锁避免多个CPU争用锁导致的CPU高速缓存颠簸互斥锁允许睡眠不能在中断处理函数等实时性要求高的场景使用 互斥锁用owner原子变量替换了count全局变量避免“读-写”的同步问题同时便于定位死锁问题。 互斥信号量是一个简陋的同步机制。 4.1.2什么是偷锁偷锁是怎么产生的   锁的持有者A用完锁理应传递给BB去A这里接手锁的时候发现锁已经在C那里了。锁在交接的过程中被C偷走了。 进程A释放锁并把B唤醒让B持锁但是巧了C在A释放锁的时候正在申请锁在看B这会儿还睡者A一释放C就抢走了等B醒来没自己啥事了。如果不好理解举一个乌鸦与狐狸的故事乌鸦嘴里衔着一块肉乌鸦准备把这块肉给正再睡觉的小乌鸦乌鸦张嘴叫小乌鸦的时候而正好被狐狸路过看见等小乌鸦醒来肉已不见了只能继续睡。 4.1.3为什么要引入乐观自旋   假设一种场景持锁的进程A即将放锁进程B发起锁的申请B看锁已被占用立即就会睡眠睡眠后立即又被A唤醒这期间在调度上的开销不可忽略。也就是说进程B不睡眠乐观的忙等开销可能比睡眠要小得多。这就是乐观自旋机制的作用。 4.1.4什么情况下该乐观且乐观多久   还有剩余时间片且owner仍然在CPU上运行。一般是50us。用户可以根据自行的实际情况来设置。 4.1.5为什么需要handoff机制     乐观自旋加剧了偷锁的概率。乐观自旋机制的加入改变了“乌鸦与狐狸”剧本上文中的狐狸恰巧撞上一块肉加入乐观自旋后狐狸盯着乌鸦嘴里的肉一段时间狐狸偷走肉的概率大大提升了。要命的是如果运气不好接下来的几天肉都被狐狸偷走小乌鸦就活活被饿死了。经过反思后就设计了HANDOFF机制来避免waiter饿死悲剧的发生。 4.1.6HANDOFF机制的原理   Wait_list上第一个waiter被唤醒后立即设置HANDOFF标记位如果锁此时被偷小偷释放锁时直接把锁交给第一个waiter在__mutex_unlock_slowpath中直接将第一个waiter的task赋值给lock-owner,这就保证了第一个waiter的锁最多被偷一次。 4.2代码实现   4.2.1关键数据结构       Owner变量的解读 Owner变量为0时表示没有持锁。非0表示持有锁。BIT2~BIT0标记位主要用于乐观自旋等待。 4.2.2关键函数接口   4.2.2.1mutex_init   Linux内核中定义了两个mutex初始化接口DEFINE_MUTEX(mutexname)与mutex_init他们实现的功能完全相同。程序员可以根据自己的偏好选其一。 主要完成struct mutex的成员变量初始化。 4.2.2.2mutex_lock     申请获取mutex锁未申请到锁将在该函数中睡眠该函数返回就表示申请获取成功申请线程将持有对应的mutex锁。 快速路径分析 申请获取mutex锁首先进入快速路径__mutex_trylock_fast如果申请失败进入慢速路径__mutex_lock_slowpath。 快速路径的实现非常简单原子的比较owner变量确认是否有其他线程已经持锁。 慢速路径分析     __mutex_lock里直接调用了__mutex_lock_common接下来展开__mutex_lock_common分析这是mutex的灵魂所在。代码比较长仅截取关键片段过滤debug代码与非arm64的代码分析。 __mutex_trylock     mutex_optimistic_spin     阅读完源代码总结一下主要流程     尝试获取锁失败进入乐观者自旋获取锁如果还是失败将当前进程加入到wait_list然后再次尝试获取锁还是失败让出CPU睡眠持锁的owner用完锁后释放并唤醒waiter唤醒后继续尝试获取锁。 乐观自旋机制mutex_optimistic_spin是为了解决性能问题对锁本身的功能没有影响。 4.2.2.3mutex_unlock   mutex_unlock直接调用了__mutex_unlock_slowpath下面注释__mutex_unlock_slowpath的实现。     4.3应用场景    资源互斥场景由于可能会存在睡眠禁止在实时性要求高的场景使用例如中断上半部中。 4.4思考   4.4.1Mutex锁申请的慢速路径里为什么进入函数就关闭了抢占如果不关闭会有什么影响   4.4.2释放锁的时候为什么不直接判断是否有waiter如果有waiter直接把锁传递给waiter这样不就避免了所有偷锁的情况吗   4.4.3不同优先级的进程不同的自旋时长会不会带来更好的体验    由于篇幅过长下章将为大家带来 5、读写信号量-rw_semaphore 6、percpu-rwsem 往 期 推 荐 深度好文 | Android高性能音频解析 干货 | 刷机流程介绍 crash实战手把手教你使用crash分析内核dump 长按关注内核工匠微信 Linux内核黑科技| 技术文章| 精选教程
http://www.zqtcl.cn/news/450343/

相关文章:

  • 宝山网站制作网站优化待遇
  • 网站建设项目竞争性招标文件界面设计的重要性
  • 网站建设合同机械设备网络推广方案
  • 阿里巴巴做网站的绿色的医疗资讯手机网站wap模板html源码下载
  • 怎么样自己做企业网站dz采集wordpress
  • 欧 美 做 爱 视频网站阿里巴巴电子商务网站建设目的
  • 动易网站后台修改栏目的字定制型网站设计价格
  • 设计网站页面临夏州建设厅官方网站
  • 给别人做网站需要什么许可证大连做网站开发的公司
  • 哪些网站国内打不开线下推广小组为了推广开放文明环境地图
  • 电子商务网站建设的核心网站收录检测
  • 厦门中小企业建网站补助源码做微信电影网站
  • 利用表单大师做网站网站备案证书放到哪里
  • 辽宁省建设科学研究院网站asp.net做网站 推荐书籍
  • 网站解决访问量超载做国外营销型网站设计
  • 思科中国网站开发案例网站如何进行建设
  • 网页设计与网站建设郑州大学怎么在传奇网站上做宣传
  • 中国建设银行重庆网站首页sns网站需求
  • 外网常用网站全网网站建设设计
  • 成都建设网站费用做数据库与网站招什么人
  • 最好的wordpress教程啥叫优化
  • 哪个网站做网销更好网站流量流出异常
  • 广州网站定做纸箱手工制作大全
  • 数据库修改网站后台密码cms三合一网站源码
  • 一般做哪些外贸网站丰南建设局网站
  • 网站如何被收录情况自己做的网站如何实现下载文件
  • 龙岩网站设计一般要多久深圳做自适应网站设计
  • 类似于拼多多的网站怎么做资料下载网站建设
  • 做商城网站哪里网站官网建设的价格
  • 网站怎么做用户体验山东富国建设投资有限公司网站