首页 > 其他分享 >30天开发操作系统 第 15 天 --多任务 v1.0

30天开发操作系统 第 15 天 --多任务 v1.0

时间:2025-01-18 09:27:47浏览次数:3  
标签:task 15 -- 30 timer 任务 切换 sht fifo

前言

话说,多任务到底是啥呢?”我们今天的内容,就从这个问题开始吧。 多任务,在英语中叫做“multitask”,顾名思义就是“多个任务”的意思。简单地说,在Windows 等操作系统中,多个应用程序同时运行的状态(也就是同时打开好几个窗口的状态)就叫做多 任务。 对于生活在现代社会的各位来说,这种多任务简直是理所当然的事情。比如你会一边用音乐 播放软件听音乐一边写邮件,邮件写到一半忽然 有点东西要查,便打开Web浏览器上网搜索。这 对于大家来说这些都是家常便饭了吧。可如果没 有多任务的话会怎么样呢?想写邮件的时候就必 须关掉正在播放的音乐,要查东西的时候就必须 先保存写到一半的邮件,然后才能打开Web浏览 器……光想象一下就会觉得太不方便了。 然而在从前,没有多任务反倒是普遍的情形(那个时候大家不用电脑听音乐,也没有互联 网)。在那个年代,电脑一次只能运行一个程序 ,如果要同时运行多个程序的话,就得买好几台 电脑才行。 就在那个时候,诞生了最初的多任务操作系统,大家都觉得太了不起了。从现在开始,也要准备给我们的系统添加执行多任务的能力了。连这样一个小不点儿操作系统都能够实现 多任务,真是让人不由地感叹它生逢其时呀。

稍稍思考一下我们就会发现,多任务这个东西还真是奇妙,它究竟是怎样做到让多个程序同时运行的呢?如果我们的电脑里面装了好多个CPU的话,同时运行多个程序倒也顺理成章,但实 际上就算我们只有一个CPU,照样可以实现多任务。 其实说穿了,这些程序根本没有在同时运行,只不过看上去好像是在同时运行一样:程序A 运行一会儿,接下来程序B运行一会儿,再接下来轮到程序C,然后再回到程序A…·如此反复。
为了让这种分身术看上去更完美,需要让操作系统尽可能快地切换任务。如果10秒才切换一 次,那就连人眼都能察觉出来了,同时运行多个程序的戏码也就穿帮了。再有,如果我们给程序 C发出一个按键指令,正巧这个瞬间系统切换到了程序A的话,我们就不得不等上20秒,才能重 新轮到程序C对按键指令作出反应。这实在是让人抓狂啊(哭)。 在一般的操作系统中,这个切换的动作每0.01~0.03秒就会进行一次。 当然, 切换的速度越 让人觉得程序是在同时运行的效果也就越好。不过,CPU进行程序切换(我们称为“任务切换”)这个动作本身就需要消耗一定的时间,这个时间大约为0.0001秒左右, 不同的CPU及操作 系统所需的时间也有所不同。 如果CPU每0.0002秒切换一次任务的话,该CPU处理能力的50%都 要被任务切换本身所消耗掉。这意味着,如果同时运行2个程序,每个程序的速度就只有单独运 行时的1/4,这样你会觉得开心吗?如果变成这种结果,那还不如干脆别搞多任务呢。 相比之下,即便是每0.001秒切换一次任务, 单单在任务切换上面也要消耗CPU处理能力的 10%。大概有人会想,10%也没什么大不了的吧 ?可如果你看看速度快10%的CPU卖多少钱,说 就相当于一分钱也不花,便换上了比 “对啊,只要优化一下任务切换间隔, 不定就会恍然大悟, 现在更快的CPU嘛…”(笑),你也就明白了浪费10%也是很不值得的。正是因为这个原因,任 务切换的间隔最短也得0.01秒左右,这样一来只有1%的处理能力消耗在任务切换上,基本上就可 以忽略不计了。

一、挑战多任务切换

关于多任务是什么的问题,已经大致讲得差不多了,接下来我们来看看如何让CPU来处理多 任务。 当你向CPU发出任务切换的指令时,CPU会先把寄存器中的值全部写入内存中,这样做是为 了当以后切换回这个程序的时候,可以从中断的地方继续运行。接下来,为了运行下一个程序, CPU会把所有寄存器中的值从内存中读取出来(当然,这个读取的地址和刚刚写入的地址一定是 不同的,不然就相当于什么都没变嘛),这样就完成了一次切换。我们前面所说的任务切换所需 要的时间,正是对内存进行写入和读取操作所消耗的时间。

接下来我们来看看寄存器中的内容是怎样写入内存里去的。下面这个结构叫做“任务状态段” (task status segment),简称TSS。TSS有16位和32位两个版本,这里我们使用32位版。顾名思义, TSS也是内存段的一种,需要在GDT中进行定义后使用。

struct TSS32 {
	int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;
	int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
	int es, cs, ss, ds, fs, gs;
	int ldtr, iomap;
};

参考上面的结构定义,TSS共包含26个int成员,总计104字节(摘自CPU的技术资料),我 特意把它们分成4行来写。从开头的backlink起 ,到cr3为止的几个成员,保存的不是寄存器的 数据,而是与任务设置相关的信息,在执行任务切换的时候这些成员不会被写入(backlink除 外,某些情况下是会被写入的)。后面的部分中我们会用到这里的设定, 不过现在你完全可以 先忽略它。 第2行的成员是32位寄存器, 第3行是16位寄存器,应该没必要解释了吧…….不对,eip好像 “extended instruction pointer”,也就是“扩展指令指针寄存器” 到现在还没讲过呢。EIP的全称是 代表它是一个32位寄存器,也就是说其对应的16位版本叫做IP,类比一 的意思。这里的“扩展” 下的话,跟EAX与AX之间的关系是一样的。 EIP是CPU用来记录下一条需要执行的指令位于内存中哪个地址的寄存器,因此它才被称为 “指令指针”。如果没有这个寄存器,记性不好的CPU就会忘记自己正在运行哪里的程序,于是程 序就没办法正常运行了。 每执行一条指令,EIP寄存器中的值就会自动累加,从而保证一直指向下一条指令所在的内存地址。

如果在TSS中将EIP寄存器的值记录下来,那么当下次再返回这个任务的时候,CPU就可以明 白应该从哪里读取程序来运行了。 按照常识, 段寄存器应该是16位的才对,可是在TSS数据结构中却定义成了int(也就是 DWORD)类型。我们可以大胆想象一下,说不定英特尔公司的人将来会把段寄存器变成32位的, 这样想想也挺有意思的呢(笑)。 第4行的ldtr和iomap也和第1行的成员一样,是有关任务设置的部分,因此在任务切换时不会被CPU写入。也许你会想,那就和第1行一样, 暂时先忽略好了 – 但那可是绝对不行的!如果胡乱赋值的话,任务就无法正常切换了,在这里我们先将ldr置为0, 将iomap置为0x40000000就好了。

说点题外话,JMP指令实际上是一个向EIP寄存器赋值的指令。JMP0x1234这种写法, CPU会解释为MOVEIP,0x1234,并向EIP赋值。也就是说,这条指令其实是基改了CPU记 蒙了CPU一把。这样一来,CPU在读取下一条指令时, 忆中下一条该执行的指令的地址,就会去读取0x1234这个地址中的指令。你看,这不就相当于是做了一个跳转吗? 对了,如果你在汇编语言里用MOV EIP,0x1234这种写法是会出错的,还是不要尝试的 好。在汇编语言中,应该使用JMP0x1234来代替MOVEIP,0x1234。

关于TSS的话题暂且先告一段落,我们回来继续讲任务切换的方法。 要进行任务切换,其实 还得用JMP指令。JMP指令分为两种, 只改写EIP的称为near模式, 同时改写EIP和CS的称为far模 在此之前我们使用的JMP指令基本上都是near模式的。 不记得CS是什么了?CS就是代码段式, (code segment)寄存器啦。 说起来我们其实用过一次far模式的JMP指令, 就在asmhead.nas的 “bootpack启动” 的最后一句(见第八天)。

JMP DWORD 2*8:0x0000001b

这条指令在向EIP存人0x1b的同时,将CS置为2*8(=16)。像这样在JMP目标地址中带冒号(

标签:task,15,--,30,timer,任务,切换,sht,fifo
From: https://blog.csdn.net/suy123/article/details/145214134

相关文章

  • 实现异步编程有哪些方式?推荐用哪种?
    实现异步编程在前端开发中有多种方式,每种方式都有其特定的使用场景和优缺点。以下是一些常见的异步编程实现方式:回调函数(Callback):回调函数是最原始且广泛使用的异步编程方式之一。当一个异步操作完成时,它会调用一个作为参数传递的函数,即回调函数,并将结果作为参数传递给该函......
  • 举例说明如何在页面中添加数学公式?
    在前端开发中,向页面添加数学公式可以通过多种方法实现,以下是一些具体的例子和步骤:使用HTML转义字符:对于简单的数学公式,如“E=mc^2”,可以直接使用HTML转义字符来表示。例如,使用<sup>标签来表示上标:<p>E=mc<sup>2</sup></p>这种方法简单易行,但仅适用于简单的公式。使用Mat......
  • 内存和缓存有什么区别?
    内存和缓存之间的区别主要体现在以下几个方面:主体不同:内存是计算机中重要的部件之一,它是外存与CPU进行沟通的桥梁,用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。缓存则是指访问速度比一般随机存取存储器(RAM)快的一种高速存储器,它可以进行高速数据交换,先于内......
  • 如何使用CSS的多列布局?
    CSS的多列布局(Multi-columnLayout)可以让你把文本内容分割成多列,就像报纸或杂志那样。这对于创建响应式设计或在有限的屏幕空间内展示大量文本特别有用。以下是如何使用CSS的多列布局的基本步骤:设置列数使用column-count属性来设置你想要的列数。例如,如果你想要三列,你可以这......
  • 说说CORS为何要区分预检请求和简单请求呢?
    CORS(Cross-OriginResourceSharing,跨域资源共享)机制中区分预检请求和简单请求的原因主要涉及Web应用的安全性、请求的特性以及服务器的处理逻辑。以下是详细的解释:安全性考虑:Web应用的安全性是CORS机制的核心关注点。浏览器默认禁止跨域请求是为了防止恶意行为,如跨站脚本攻......
  • 说说你对small标签的认识,有哪些应用场景?
    在前端开发中,<small>标签是一个十分有用的HTML元素,以下是关于<small>标签的详细解释及其应用场景:一、认识<small>标签定义与功能:<small>标签用于表示文本的大小减小,它可以将文本的字体大小减小一个级别,如从small变为x-small。然而,当文本已经是最小字号时,该标签将不再产生影......
  • golang 使用 http 连接池
    最近生产碰到的问题,A程序调用B服务某接口,在大流量场景下,B接口偶尔返回503,B是java写的,A是golang编写的。经沟通,B接口最大QPS为2000,且无优化空间,A这边大概20个并发线程,B加大了连接数配置。仍然是这样错误,‌503错误‌,即“服务不可用”,通常表示服务器暂时无法处理......
  • 你有使用过FTP吗?你知道FTP它的作用是什么吗?
    是的,我使用过FTP,并且对其作用有清晰的了解。FTP,即文件传输协议(FileTransferProtocol),主要用于在网络上进行文件的双向传输。以下是关于FTP作用的详细解释:提供文件传输服务:FTP允许用户将自己的计算机与世界各地运行FTP协议的服务器相连,从而访问服务器上的大量程序和信息。这是F......
  • 27 Xbox蓝牙连接不稳定,游戏中断联,新手柄,反映延持,忽然失联的解决方法,蓝牙连接后无法自
    27新买了一个Xbox,蓝牙连接后有时会突然断联,游戏中会忽然失灵一般新手柄硬件绝对没问题,电脑自己的硬件以及软件驱动也没问题,那就是手柄自带驱动不行,!更新!一个新手柄驱动的即可解决方法1.下载一个软件“XboxAccessories”,微软商店或者网上直接找均可,我这用的网络的网址,因为微软......
  • 举例说明在css3中怎么实现背景裁剪?
    在CSS3中,你可以使用background-clip属性来实现背景裁剪。background-clip属性定义背景的绘制区域,也就是说,它决定了背景图像或背景色应该显示到哪个边界为止。这个属性有四个可能的值:border-box、padding-box、content-box和text。下面是一个简单的例子来说明如何使用background-c......