二、xv6的锁

为了在多处理器上防止多个CPU操作同一片地址空间互相干扰引起的错误,以及即使是在单个处理器上防止中断处理程序与非中断代码之间互相干扰,xv6使用锁来实现互斥。

2.1代码阅读与分析

xv6定义锁的代码非常明确,即spinlock和sleeplock。spinlock会在无法获得锁时不断循环获取;而sleeplock为了防止长时间的等待循环,在获取不到锁时让进程陷入睡眠,锁释放时对睡眠进程进行唤醒。

2.1.1spinlock.h

spinlock.h定义了spinlock的数据结构,一个指向持有锁的CPU的指针,一个名字指针,核心是一个整数locked,值为0代表没有锁,值为1代表锁了。

2.1.2spinlock.c

包含了一系列spinlock的操作。

initlock()初始化锁的成员变量,将locked置为0。

acquire()使得当前进程获取指定名称的锁。首先使用push_off关中断以避免死锁(进程持有锁后发生中断,中断程序等待锁,导致中断无法返回,陷入死锁)。然后检查当前进程是否已经获取了这把锁,若获取则将panic。在这里,函数使用了riscv的原子操作来避免直接写while语句可能产生的并发错误。__sync_lock_test_and_set等效于以下代码,但是是一个原子操作,并在成功获取时返回0。随后函数将告知C编译器不能在优化时改变此处语句的前后顺序,以免出现错误。

while(1){  if(!lk->locked){  lk->locked=1;  break;  }
} 

release()首先检查是否持有锁,如果无锁release就会引发panic。与获取锁的操作相同,需要__sync_synchronize,并使用原子化的操作__sync_lock_release来将locked置为0,最后使用pop_off开中断。

holding()检查当前进程是否持有某个锁,通过检查locked和cpuid。

push_off和pop_off是开关中断的函数。与intr_on/off不同的是多了计次功能,n个push_off需要n个pop_off来完全释放,就像push和pop的操作。

2.1.3 sleeplock.h

sleeplock.h定义了睡眠锁的结构包含记录是否已经被持有的locked和保护sleeplock的spinlock,还有pid和锁名。

2.1.4 sleeplock.c

initsleeplock()通过调用initlock()和赋值来对锁初始化。

acquiresleep()在获取sleeplock的过程中使用其中的spinlock保证函数的原子性。先获取对应的spinlock,然后判断要获取的锁是否已被持有,如果被持有则进入睡眠,当从睡眠醒来时,需要重新获取spinlock。如果可以获取锁,就改变locked和pid,然后释放spinlock。进入sleep函数时,会获取当前进程的lock,然后释放sleeplock的自旋锁,而sleep函数结束时会释放进程的锁,获取睡眠锁的锁。函数采用while语句,让每次进程被唤醒时都检查等待的条件是否满足,防止出现一个睡眠进程等待的锁没有空闲就被唤醒的情况。

releasesleep()同样使用自旋锁维护原子性,释放时把锁的pid和locked值设为0,然后使用wakeup函数,实际上是对设置进程状态p->state=RUNNABLE的包装。

holdingsleep()的操作与holding()相同。

2.2锁的使用

锁的使用非常简单,先声明锁,然后在初始化函数中把锁初始化,使用时在语句前后分别获取释放即可,但也有一些注意事项。

2.2.1 锁的顺序

如果一段代码要使用多个锁,那么必须要注意代码每次运行都要以相同的顺序获得锁,并以相反的顺序释放锁,否则就会发生死锁。假设某段代码中存在两条路径,路径1获得锁的顺序是 A、B,而路径2获得锁的顺序是 B、A。那么就可能1中持有A,2中持有B,二者互相等待无法继续运行,发生死锁。为了避免死锁,所有的代码路径获得锁的顺序必须相同。同样的,释放锁必须以获得的相反顺序运行。加锁的操作就像给代码加上花括号,内层对应内层,外层对应外层。

2.2.2 锁的粒度

在代码中使用一把大锁对于编码来说非常简单,但也牺牲了并发性能,极大地影响着程序的效率。因此,为了发挥多处理器的性能,需要设计细粒度的锁并恰当地编码以保证锁的正确性。正如我们在lab中为每个哈希桶或者每个CPU设计一把锁。

2.2.3 锁的选择

使用自旋锁基本保证了同步互斥问题能得到解决,但效率似乎并不理想,因为他是忙等待的,将一直占有CPU执行循环,所以引入了睡眠锁,让得不到锁的进程进入睡眠状态让出CPU重新调度。因此如果锁持有的时间较长,可能需要使用睡眠锁。

使用锁的一个难点在于要决定使用多少个锁,以及每个锁保护哪些数据、不变量。不过有几个基本原则。首先,当一个 CPU 正在写一个变量,而同时另一个 CPU 可能读/写该变量时,需要用锁防止两个操作重叠。第二,当用锁保护不变量时,如果不变量涉及到多个数据结构,通常每个数据结构都需要用一个单独的锁保护起来,这样才能维持不变量。

2.3小结

锁的机制比较简单,但在其他各个模块中都有广泛的应用。

XV6 RISCV源码阅读报告之 锁相关推荐

  1. XV6 RISCV 源码阅读报告之 进程调度

    xv6阅读之进程调度 四.进程调度 在计算机资源不足以同时运行所有进程时,就需要操作系统考虑如何分配有限的资源,如CPU时间和内存.xv6通过切换每个CPU上的进程实现多路复用.当进程等待设备或管道I ...

  2. XV6 RISCV源码阅读报告之中断

    一.xv6中断异常 在操作系统运行用户进程时处于用户态,当发生异常.中断或陷入时,需要从用户态进入内核态调用处理机制.陷入内核之前需要保存上下文,而在处理完成,回到用户态时需要恢复上下文.代码包括tr ...

  3. XV6 RISC-V 源码阅读报告之进程模型

    三.xv6进程模型 进程是对运行程序的抽象,通过CPU调度和虚拟地址等机制,为每个程序提供了独占处理器和内存空间的错觉. 3.1代码阅读 代码主要在proc.h和proc.c 3.1.1proc.h ...

  4. XV6 RISCV源码阅读之 虚拟内存

    五.内存管理 通过进程线程模型,xv6为每个程序提供了独占处理器的错觉,而通过虚拟内存,xv6为程序提供了统一的0-MAXVA地址的虚拟内存,并通过页表进行内存的管理.RISCV页表通过将每个虚拟地址 ...

  5. XV6 RISCV 源码阅读之文件系统

    六.文件系统 xv6的文件系统分为七层,由低到高如下所示. 磁盘层读取和写入virtio硬盘上的块. BufferCache层缓存磁盘块,同步对他们的访问. 日志层允许更高层在一次事务中将更新包装到多 ...

  6. NS3-LENA源码阅读报告(2)

    2 LENA源码组成结构 LENA作为NS3的程序模块,采用标准的NS3模块结构内容来对代码进行组织.这种标准结构内容可以通过NS3提供的create-module.py来进行创建,也可以依照惯例进行 ...

  7. xv6操作系统源码阅读之init进程

    首先看main函数,里面调用了一个userinit函数,这就是启动第一个init进程. // Bootstrap processor starts running C code here. // Al ...

  8. NS3-LENA源码阅读报告(1)

    动态系统仿真通过连续的时间步仿真用户在网络中的移动性和其它特性,构成时间驱动的状态机.仿真过程将实际的网络环境.通信协议和用户行为等抽象为数学模型,然后借助于编程语言和软件框架进行实现.NS3是基于离 ...

  9. Java多线程——重入锁ReentrantLock源码阅读

    上一章<AQS源码阅读>讲了AQS框架,这次讲讲它的应用类(注意不是子类实现,待会细讲). ReentrantLock,顾名思义重入锁,但什么是重入,这个锁到底是怎样的,我们来看看类的注解 ...

最新文章

  1. 遍历文件夹_使用JavaScript遍历本地文件夹的文件
  2. AddressBookUI.Framwork应用之ABPersonViewController, ABUnknownPersonViewController,ABNewPersonViewContro
  3. ss.exe 命令参数应用
  4. 丁奇 mysql_丁奇-MySQL实战读书笔记4
  5. oracle中 rownum与rowid的理
  6. [GO]append的扩容
  7. 如何使用Emacs Org模式和Reveal.js创建幻灯片
  8. oracle 查看白名单,oracle配置访问白名单教程
  9. oracle初级系列教程
  10. python简单选择排序_Python实现冒泡,插入,选择排序简单实例
  11. Android 进程的五种生命周期学习
  12. AI企航58自动发帖软件图片视频教程
  13. 只需简单一步,android自带的示例程序 BluetoothChat 变蓝牙串口助手
  14. 咪咕音乐HTML代码,python3爬取咪咕音乐榜信息(附源代码)
  15. 软件需求,概要设计,详细设计(文档)
  16. python中isalpha()、isdigit()、isalnum()、isupper()、islower()的含义、区别和细节
  17. 【揭秘】CSDN博客上,超过百万访问量的Android牛人都是谁?
  18. php orm中关联查询,【整理】Laravel中Eloquent ORM 关联关系的操作
  19. 无盘服务器 显卡,我也来说说网吧配机器该用什么显卡
  20. 智安荣誉丨智安【一站式等保云平台】荣获第六届“创客中国”网络安全中小企业创新创业大赛优胜奖!

热门文章

  1. 剑指 Offer 40. 最小的k个数
  2. 【无标题】chatgpt桌面化,桌面应用的安装
  3. Windows Azure 常见问题汇总
  4. java从小白到老白②
  5. RPA - Robotic process automation (机器人流程自动化)
  6. 29种Bokeh基础可视化图形
  7. 关于Android项目中的Toast那些动画实现方式
  8. nbu恢复mysql_使用NBU进行oracle异机恢复
  9. vue组件加载完成之后执行方法_vue-cli监听组件加载完成的方法
  10. omniplan导出html,OmniPlan 3.14.4 最NB的项目管理流程软件