xv6 中的一些系统调用(下)

〇、前言

本文将会结合源代码谈论 sleep、wakeup 这两个系统调用。

一、sleep()系统调用

以下是sleep()函数源码:

// Atomically release lock and sleep on chan.
// Reacquires lock when awakened.
void
sleep(void *chan, struct spinlock *lk)
{struct proc *p = myproc();// Must acquire p->lock in order to// change p->state and then call sched.// Once we hold p->lock, we can be// guaranteed that we won't miss any wakeup// (wakeup locks p->lock),// so it's okay to release lk.acquire(&p->lock);  //DOC: sleeplock1release(lk);// Go to sleep.p->chan = chan;p->state = SLEEPING;sched();// Tidy up.p->chan = 0;// Reacquire original lock.release(&p->lock);acquire(lk);
}

先来看看 lost wakeup 问题。当一个进程在 sleep() 时,如果 sleep() 了一半,状态还没来得及修改为SLEEPING,这时候发生了中断,并且被某些进程调用了 wakeup(),那么这个 wakeup()肯定不能把这个进程唤醒。而且,在被中断恢复后,它将永远等不到唤醒,因为唤醒已经错过。所以,在这里必须要正不可中断性和操作先后性。因为在下面就会看到 wakeup() 只唤醒状态为 SLEEPING 的进程。

因此我们必须保证,sleep() 是一个原子操作,在 sleep() 执行过程中,要么执行完全,要么没有被执行。所以这里必须加一个进程锁。所以在下面就会看到 wakeup() 中也会尝试获取休眠的进程锁。

在持有进程锁的时候,将进程的状态设置为 SLEEPING 并记录sleep channel,之后再调用 sched() 函数,这个函数中会再调用 swtch() 函数(而这会返回到 scheduler()函数中),此时 sleep() 函数中仍然持有了进程的锁,wakeup() 仍然不能做任何事情。

因此在 sleep()之后,这个锁必须释放。我们来看看细节:

void
scheduler(void)
{...swtch(&c->context, &p->context);// Process is done running for now.// It should have changed its p->state before coming back.c->proc = 0; // 返回的位置,此刻继续执行}release(&p->lock);...
}

在这里,它会继续执行上一次执行到的位置,即 c->proc = 0,然后执行 release(&p->lock),也就是释放锁,而且释放的是 sleep() 中的当前进程的锁。(这一点不是很好理解,可以理解为用的上一个进程的代码释放当前进程的锁?总之,这些代码就冰冷冷的放在内存里,被 pc 不断地指一遍又一遍)。更有意思的是,在 sched() 函数返回之后,继续运行:

void
sleep(void *chan, struct spinlock *lk)
{...sched();// Tidy up.p->chan = 0; // 就绪执行的位置// Reacquire original lock.release(&p->lock);acquire(lk);
}

这里 release(&p->lock) 实际上释放的是 scheduler() 中选中的进程的锁。

所以在调度器线程释放进程锁之后,wakeup() 才能终于获取进程的锁,发现它正在 SLEEPING状态,并唤醒它。

这里的效果是由之前定义的一些规则确保的,这些规则包括了:

  • 调用 sleep 时需要持有condition lock,这样 sleep 函数才能知道相应的锁;
  • sleep函数只有在获取到进程的锁 p->lock之后,才能释放 condition lock;
  • wakeup需要同时持有两个锁才能查看进程。

二、wakeup()调用

以下是 wakeup() 的源码:

// Wake up all processes sleeping on chan.
// Must be called without any p->lock.
void
wakeup(void *chan)
{struct proc *p;for(p = proc; p < &proc[NPROC]; p++) {if(p != myproc()){acquire(&p->lock);if(p->state == SLEEPING && p->chan == chan) {p->state = RUNNABLE;}release(&p->lock);}}
}

可以看到它的工作很简单,检查两个条件之后,就修改进程的状态为 RUNNABLE。

三、总结

这篇文章详细地介绍了 xv6 操作系统中的 sleep() 和 wakeup() 系统调用的实现原理以及相关的内部工作机制。主要强调了在 sleep() 中的原子操作性,确保了操作的完整性,以及在 wakeup() 中唤醒休眠进程的方式。

关于 sleep():

强调了 sleep() 操作的原子性,使用进程锁确保 sleep() 操作是一个原子操作,避免了 “lost wakeup” 问题的发生。
通过释放持有的锁,让出 CPU 控制权,进入 SLEEPING 状态,然后释放进程锁,使得其他进程能够继续运行。
调度器在合适的时机恢复了进程的执行,完成 sleep() 操作。

关于 wakeup():

wakeup() 通过遍历进程列表,并获取每个进程的锁,查看处于 SLEEPING 状态且 sleep channel 匹配的进程,将其状态设置为 RUNNABLE,唤醒进程。

整体上,这篇文章清晰地解释了 sleep() 和 wakeup() 这两个关键系统调用的工作原理和实现细节,突出了在并发环境下确保原子性操作和避免死锁的重要性。

全文完,感谢阅读。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/news/213733.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无线且列窄图片如何转excel?

写此文原因&#xff1a;图片要转excel&#xff0c;这放以前&#xff0c;是不能实现的功能&#xff0c;但随着人工智能的蓬勃发展&#xff0c;人们已克服了这一难题&#xff0c;但是&#xff0c;我们知道&#xff0c;要将图片识别成excel&#xff0c;识别程序首先要先识别图片中…

如何在小米路由器4A千兆版刷入OpenWRT并通过内网穿透工具实现公网远程访问

文章目录 前言1. 安装Python和需要的库2. 使用 OpenWRTInvasion 破解路由器3. 备份当前分区并刷入新的Breed4. 安装cpolar内网穿透4.1 注册账号4.2 下载cpolar客户端4.3 登录cpolar web ui管理界面4.4 创建公网地址 5. 固定公网地址访问 前言 OpenWRT是一个高度模块化、高度自…

交易历史记录20231206 记录

昨日回顾&#xff1a; select top 10000 * from dbo.CODEINFO A left join dbo.全部&#xff21;股20231206010101 B ON A.CODE B.代码 left join dbo.全部&#xff21;股20231206CONF D on A.CODED.代码left join dbo.全部&#xff21;股20231206 G on A.CODEG.代码 left…

解决前端跨域问题,后端解决方法

Spring CloudVue前后端分离项目报错&#xff1a;Network Error&#xff1b;net::ERR_FAILED&#xff08;请求跨越&#xff09;-CSDN博客记录自用

Kafka-快速实战

Kafka介绍 ChatGPT对于Apache Kafka的介绍&#xff1a; Apache Kafka是一个分布式流处理平台&#xff0c;最初由LinkedIn开发并于2011年开源。它主要用于解决大规模数据的实时流式处理和数据管道问题。 Kafka是一个分布式的发布-订阅消息系统&#xff0c;可以快速地处理高吞吐…

阿里云国际基于CentOS系统镜像快速部署Apache服务

阿里云轻量应用服务器提供了Windows Server系统镜像和主流的Linux系统镜像&#xff0c;您可以通过该类镜像创建纯净、安全、稳定的运行环境。本文以CentOS 7.6系统镜像为例&#xff0c;介绍如何快速配置Apache服务。 背景信息 注意&#xff0c;阿里云国际通过corebyt注册并充…

使用rawpy.imread读取.RAW格式数据和.dng格式数据(附代码)

.dng格式是一个更兼容、更高效的RAW格式。如果需要在不同软件之间交换RAW文件&#xff0c;或者需要在软件中进行大量编辑&#xff0c;那么.dng格式是一个不错的选择。 目录 一、 .dng格式数据和.RAW格式数据二、 .dng格式数据和.RAW格式数据区别三、安装rawpy包四、读取.dng格式…

Flask应用基础入门总结

【1】使用migrate方式进行数据库连接 使用migrate方式进行数据库连接需要在终端分别运行三行代码&#xff1a; #init&#xff08;运行一次即可&#xff09;&#xff08;此db为自己设置的连接数据库的对象,可以修改&#xff09; flask db init #&#xff08;将orm模型生成迁移…

从零开始搭建企业管理系统(四):集成 Knife4j

集成 Knife4j 前言Knife4j是什么集成 Knife4j引入 pom 依赖添加基础配置启动程序测试完善文档信息编写配置类修改 UserController修改 UserEntity修改 BaseEntity 文档效果图swagger 界面knife4j 界面 前言 前面一小节我们使用postman来进行接口的调试&#xff0c;如果接口一多…

游戏王的题解

目录 原题&#xff1a; 时间&#xff1a;1s 空间&#xff1a;256M 题目描述 输入格式 输出格式 样例输入 样例输出 题目大意&#xff1a; 主要思路&#xff1a; dp转移&#xff1a; dp初始化&#xff1a; 代码&#xff1a; 原题&#xff1a; 时间&#xff1a;1s …

springboot集成knife4j详细教程

使用原生的swagger作为接口文档&#xff0c;功能不够强大&#xff0c;并且默认的ui比较简陋&#xff0c;不符合大众审美。所以实际开发中推荐使用knife4j对swagger进行增强。knife4j的地址&#xff1a;https://gitee.com/xiaoym/knife4j 基本使用 想要使用knife4j非常简单&…

深入学习Redis:从入门到实战

Redis快速入门 1.初识Redis1.1.认识NoSQL1.1.1.结构化与非结构化1.1.2.关联和非关联1.1.3.查询方式1.1.4.事务1.1.5.总结 1.2.认识Redis1.3.安装Redis1.3.1.依赖库1.3.2.上传安装包并解压1.3.3.启动1.3.4.默认启动1.3.5.指定配置启动1.3.6.开机自启 1.4.Redis桌面客户端1.4.1.R…

【VS Code开发】使用Live Server搭建MENJA小游戏并发布至公网远程访问

文章目录 前言1. 编写MENJA小游戏2. 安装cpolar内网穿透3. 配置MENJA小游戏公网访问地址4. 实现公网访问MENJA小游戏5. 固定MENJA小游戏公网地址 前言 本篇教程&#xff0c;我们将通过VS Code实现远程开发MENJA小游戏&#xff0c;并通过cpolar内网穿透发布到公网&#xff0c;分…

C++ //习题3.8 写出下面各逻辑表达式的值。设a=3,b=4,c=5。

C程序设计 &#xff08;第三版&#xff09; 谭浩强 习题3.8 习题3.8 写出下面各逻辑表达式的值。设a3&#xff0c;b4&#xff0c;c5。 (1) a b > c && b c (2) a || b c && b - c (3) !(a > b) && !c || 1 (4) !(x a) && (y b…

FastAPI之响应状态码

使用FastAPI自定义响应状态码 FastAPI 是一个现代、快速的 web 框架&#xff0c;用于构建API服务&#xff0c;它允许你通过Python 3.6及以上版本进行编程。一个重要的API设计是返回合适的响应状态码&#xff0c;这可以使得客户端理解服务端的处理结果。本教程将向你展示如何在…

推出 Amazon EC2 C7i 实例

亚马逊云科技宣布全面推出由定制的第 4 代英特尔至强可扩展处理器&#xff08;代号为 Sapphire Rapids&#xff09;提供支持的 Amazon Elastic Compute Cloud (Amazon EC2) C7i 实例。这些定制处理器仅在亚马逊云科技上可用&#xff0c;与其他云提供商使用的基于 x86 的同类英特…

Kafka事务是怎么实现的?Kafka事务消息原理详解

目录 一、Kafka事务性消息1.1 介绍Kafka事务性消息1.2 事务性消息的应用场景1.3 Kafka事务性消息的优势 二、Kafka事务性消息的使用2.1 配置Kafka以支持事务性消息生产者配置消费者配置 2.2 生产者&#xff1a;发送事务性消息创建Kafka生产者开始事务发送消息提交或中止事务 2.…

logstash之grok插件自定义规则学习

文章目录 1、前言2、Grok提供的常用Patterns说明及举例2.1 常用的表达式说明 3、使用grok插件进行日志字段处理4、案例1&#xff1a;处理nginx的日志4.1、查看nginx日志格式4.2、对nginx的日志进行过滤处理 5、案例2&#xff1a;处理tomcat的日志5.1、[安装logstash-filter-mul…

外包干了3个月,技术退步明显.......

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…