知识复盘:操作系统的作用
操作系统的作用
该部分博客为自己在学习《程序员的自我修养:链接、装载与库》的时候对于过去零碎知识点的一个整理和复盘,并非照搬原文,其中会加入一些自己的联想与理解,如有错误还请指出。
操作系统在计算机中主要有两个功能:
对硬件资源进行管理,让硬件尽可能高效的解决问题或执行操作
提供抽象的接口,以便于程序对计算机的硬件资源进行调用
CPU的调度
在计算机的使用过程中,需要消耗时间的任务部分大致可以分为两种情况:
- 消耗CPU算力的计算密集型操作
- 需要等待设备响应处理的I/O密集型操作
我们知道在计算机中有南桥和北桥两个概念,北桥连同了CPU等高速芯片,而南桥则负责了磁盘、鼠标、键盘等低速设备。因此我们可以抽象出一个结论:计算密集型操作 和 I/O密集型操作 是由不同的设备分别处理的。接下来对于操作系统调度分析则会都以这一前提条件进行分析。
第一阶段:多道程序 Multiprogramming
假设我们现在需要完成一个很复杂的数学问题,且假设完成这个数学问题分为两个步骤:
- 在草稿纸上"随意"的打草稿并推演计算过程,最终计算出答案(计算密集型操作)
- 将整个推演过程有条理并工整的誊抄在答卷上,便于他人阅读自己的答案(I/O密集型操作)
那么如果我们有很多个这样的题目需要完成。那么最高效的方法自然是分配两个同学A和B。假设同学A的计算能力很强,同学B的书写则十分端正,同时可以看懂同学A的草稿,那么我们便可以让同学A只需要负责计算和打草稿,只要做完了第一题就直接开始写第二题,而同学B则在同学A开始计算第二题的过程中开始誊抄第一题的答案。这样便可以让同学A和同学B的时间都统筹利用起来,以此提升效率。
在计算机中也是同样的道理。在计算机刚刚发展的时候,每次执行一个任务都需要先让CPU计算完后,CPU还要等待诸如打印机等设备输出了结果以后,再进行下一个问题的计算。
为了解决这个问题,人们便想到使用一个监控程序来监管CPU的运算,当监控程序发现在CPU进行完毕某一次运算以后,如果后续还有其他问题需要使用CPU进行计算的话,则让CPU直接进行下一个问题的计算,而不是等待第一个问题的I/O操作进行完毕以后再进行第二个问题的计算。这就是多道程序的雏形
第二阶段:分时系统 Time-Sharing System
但是随着计算机功能的逐步发展,多道程序则体现出了一个弊端:那就是任务的执行需要所有人都依次排队,前面的人如果没有解决他的问题就轮不到下一个人。
假设在银行中有一个人的业务处理需要花费特别特别长的时间,从而导致后面所有人直到银行下班都没完成自己的业务,这无疑是非常令人恼火的一件事情。但是如果这个人将自己的一个任务拆分成多个不同的部分,每完成一个部分就让后面的人先处理下,这样相对而言就能顾及他人的感受,有利于提高处理问题数量的效率。
因此,我们就了分时系统的概念,在分时系统中,程序可以通过在编写的时候主动调用某个“系统调用”来实现通知操作系统我现在这部分的工作已经完成了一部分,如果后面有其他任务需要执行的话可以先执行其他的任务,再来执行我的任务。从而在一定程度上解决了阻塞问题。
第三阶段: 多任务系统 Multi-tasking
但是分时系统在计算机的衍变过程中也展现出了自己的弊端。
依据以下两个分时系统的特点:
- 是否让出CPU是由程序自身决定的。程序需要主动调用特定的系统调用来通知操作系统它愿意让出CPU。
- 这种机制的问题是,如果一个程序不主动让出CPU(例如,由于编程错误或恶意行为),那么操作系统不能强制地从该程序中夺回CPU控制权。因此,其他程序可能会被迫等待,导致整个系统的响应性下降。
假设我们遇到一个程序员在程序中忘记调用分时的“系统调用”,还写了一个死循环的错误代码。那么整个操作系统都将会因为这个问题而出现宕机。
由此我们就需要一个更高端的操作系统来解决我们的问题,即现代操作系统的解决方案:多任务系统。
多任务系统的基础是建立在此时操作系统对所有硬件资源进行了直接的接管。而所有的应用程序都以进程(Process)的方式运行在操作系统这个大Boss之下。所有进程的调度都需要受到操作系统的管理,并且每个进程和进程之间就像是一个小房间,他们的地址空间也都是相互隔离且独立的。
在这种情况下,CPU就变成了操作系统大Boss来进行管理的一个资源,而不是和之前分时系统一样由应用自己直接对CPU进行管理了。这样的好处是可以让所有程序都听操作系统这个领导的话,而不是和之前一样我想一直占用CPU就一直占用,如果我不调用接口主动释放CPU你们谁都别想用上CPU。
对于操作系统来说,每个进程就是一个任务,每个任务则又有自己的任务优先级。对于优先级高的任务,操作系统会先进行;对优先级低的任务则后执行。如果一个进程的运行时间超过了某个限制,则会将该程序暂停以分配给其他同时间内也许更需要CPU资源的线程任务。
在此基础上还会牵扯到一些诸如多级反馈队列、上下文切换开销等问题。这里就不做过多的展开。
这里放一个之前写OSTEP课后实验相关的博客链接,便于自己查阅
设备驱动
有关于设备驱动的内容直接概述过于枯燥无味,因此下面这段解释为使用 GPT-4 生成的一个概述,觉得生动有趣就搬上来了
想象一下,你正在玩一个超级复杂的电子游戏,但你只需要按下一个按钮,就能完成一个复杂的动作,比如打怪兽或跳跃。这个按钮就像是操作系统,而那些复杂的动作就是硬件的操作。你不需要知道每一个细节,只需要按下按钮,游戏就会为你完成所有的事情。
操作系统就是这样的“神奇按钮”。它位于硬件之上,为上层的应用程序提供了一个统一的方式来访问硬件。想象一下,如果每次你想在屏幕上画一条线,都需要知道你的电脑使用的是什么显卡、屏幕的大小和分辨率,然后写一大堆复杂的代码。这听起来很麻烦,对吧?但是,有了操作系统,你只需要调用一个简单的函数,比如LineTo()
,然后操作系统会为你处理所有的细节。
在操作系统的早期,程序员确实需要直接与硬件交互,这是一件非常繁琐和复杂的事情。但随着时间的发展,操作系统逐渐成熟,它开始为程序员提供了一系列的“抽象”概念,使得程序员可以更加轻松地开发应用程序,而不需要关心硬件的细节。比如,在UNIX系统中,访问硬件设备就像访问普通文件一样简单;在Windows系统中,图形和声音设备被抽象成了特定的对象。
但是,谁来处理这些复杂的硬件操作呢?答案是:硬件驱动程序。它们是操作系统的一部分,专门负责与特定的硬件设备交互。这些驱动程序通常由硬件制造商开发,而操作系统提供了一系列的接口和框架,使得这些驱动程序可以在操作系统上运行。
最后,让我们以读取文件为例。当你想读取一个文件时,你不需要知道这个文件在硬盘上的具体位置。你只需要告诉操作系统你想读取的文件名,然后操作系统会找到这个文件在硬盘上的位置,读取它,并将数据返回给你。这一切都是由文件系统和硬盘驱动程序共同完成的。
总之,操作系统就像是一个超级英雄,它为我们处理了所有复杂的硬件操作,使得我们可以更加轻松地开发和使用计算机程序。