likes
comments
collection
share

《操作系统导论》学习笔记一:操作系统简介

作者站长头像
站长
· 阅读数 22

作为一个程序员,我认为计算机组成原理、数据结构、算法和操作系统的理论知识是基础中的基础。正所谓,万变不离其宗,只有基础打好了,在新的编程技术层出不穷的时代,才会利于不变之地。

《操作系统导论》是[美]雷姆兹·H·阿帕希杜塞尔、[美]安德莉亚·C·阿帕希杜塞尔夫妇共同编写的一遍关于操作系统基础知识的书。本书深入的讲解了操作系统的三大主题:虚拟化、并发和持久化

本文是该书的第2章《操作系统介绍》的笔记。我整理了以下提纲: 《操作系统导论》学习笔记一:操作系统简介

操作系统是什么

一台电脑(或叫计算机)有硬件软件两部分组成。硬件就是我们能摸到的键盘、鼠标、显示器、硬盘、内存、CPU等这些东西。如下:

《操作系统导论》学习笔记一:操作系统简介

软件就是我们用编程语言编写出来的,运行在硬件之上的应用程序。比如我们常用的WPS、微信、QQ等。

操作系统本质上也是软件但它介于应用软件和硬件之间其作用就是管理电脑上的所有硬件资源,并把这些硬件资源合理的分配给其上的应用软件同时,它还提供了一组API接口供其上的应用软件来调用,以便让应用软件来使用其下的硬件资源

《操作系统导论》学习笔记一:操作系统简介

简而言之,操作系统的功能就是让应用程序更易于使用以及高效的运行在计算机(或叫电脑)的硬件资源上。

那么,操作系统是如何只在一组硬件基础之上,让尽量多的应用程序同时高效的运行的呢?那就是虚拟化。就是说操作系统会将物理资源(CPU、内存或磁盘)进行转换,转换成更通用、更强大的虚拟形式。

虚拟化CPU

假设机器只有一个CPU。那么,要想让机器“同时”运行多个程序,比如听歌和打游戏,就需要在操作系统和硬件的协同下,将单个CPU转换成看似是无数多个CPU,让每个程序都认为自己有一个CPU,这就是所谓的CPU虚拟化

虚拟化CPU的目的就是为了让机器能够同时运行多个程序,提高CPU的利用率

CPU虚拟化的基本原理就是分时复用。CPU一个时刻只能运行一个程序,要想达到同时运行A和B的目的,就需要一个时刻内CPU运行程序A,然后下一个时刻运行程序B,一直这样不停切换,由于CPU的运行速度相对于人来说非常快,就达到了看似同时运行程序的效果。

《操作系统导论》学习笔记一:操作系统简介

下面通过一个C语言的例子来说明虚拟化CPU后的效果。

1 #include <stdio.h> 
2 #include <stdlib.h> 
3 #include <sys/time.h> 
4 #include <assert.h> 
5 #include "common.h" 
6 
7 int 
8 main(int argc, char *argv[]) 
9 { 
10	if (argc != 2) { 
11 		fprintf(stderr, "usage: cpu <string>\n"); 
12 		exit(1); 
13 	} 
14 	char *str = argv[1]; 
15 	while (1) { 
16 		Spin(1); 
17 		printf("%s\n", str); 
18 	} 
19 	return 0; 
20 }

该程序就是读取输入,并一直循环输出读到的输入,直到输入Ctrl+C来强制终止该程序。

我们将该文件保存为cpu.c文件,并在一个单CPU的机器上编译并运行它,当然现在不太好找单核的CPU了。没关系,我们主要是为了理解其原理。

prompt> gcc -o cpu cpu.c -Wall 
prompt> ./cpu "A" 
A
A
ˆC 
prompt>

接下来,我们同时运行同一个程序的多个不同的实例。如下:

prompt> ./cpu A & ; ./cpu B & ; ./cpu C & ; ./cpu D & 
[1] 7353 
[2] 7354 
[3] 7355 
[4] 7356 
A 
B 
D 
C 
A 
B 
D 
C 
A 
C 
B 
D 
...

可以看到,尽管只有一个CPU,但你会感觉这4个程序在同时运行(如果是顺序运行的话,就会一直输出A,而不会输出其他的字母)

通过实例证明,在硬件的帮助下,操作系统负责将CPU转换成了无数多个虚拟CPU,从而让程序看似在同时运行。

虚拟化内存

首先,从硬件角度来讲,计算机提供的内存模型就是一块大的一维的字节数组。并且给每块内存分配了一个全局唯一的地址。这样在读取或写入内存时,只要指定了地址,就能知道要写入或读取内存的位置。

在多个进程同时运行的时代,每个进程都需要将自己的指令(程序)和数据加载到内存中。如果内存的一个位置被一个进程存储了数据,那么就不能再存储其他进程的内容了。其他进程的指令和数据就需要存储到内存的其他位置。

如果让每个软件自己选择可存储的内存位置,那么软件开发就会变的很复杂。那么,为了让应用软件开发变的简单,找寻可存储内存位置的工作就交给了操作系统,让操作系统来管理内存,并分配给应用进程。这就是要虚拟化内存的目的。 《操作系统导论》学习笔记一:操作系统简介

同样,下面也通过一个代码实例来演示了操作系统对内存进行虚拟化后的效果。通过运行该程序的一个实例和同时运行多个实例,发现每个实例打印出来的内存地址都是一样的,这说明操作系统对内存进行了抽象,每个进程都有自己独立的内存,并且地址空间都是一样的。只不过这是虚拟的地址空间,实际存储的位置是由操作系统经过转换后映射到了物理内存上。

1 #include <unistd.h> 
2 #include <stdio.h> 
3 #include <stdlib.h> 
4 #include "common.h" 
5 
6 int 
7 main(int argc, char *argv[]) 
8 { 
9 	int *p = malloc(sizeof(int)); // a1 
10 	assert(p != NULL); 
11 	printf("(%d) memory address of p: %08x\n", 
12 	getpid(), (unsigned) p); // a2 
13 	*p = 0; // a3 
14 	
    while (1) { 
15 		Spin(1); 
16 		*p = *p + 1; 
17 		printf("(%d) p: %d\n", getpid(), *p); // a4 
18 	} 
19 	return 0; 
20 }

并发

并发问题的发生有两个条件:同时运行多个进程或线程以及这些进程或线程需要共享相同的资源(比如内存)

并发问题最早出现的地方就是在操作系统上,因为操作系统上要同时运行多个程序,但硬件资源是共享的。同时也存在于多线程程序中,多线程共享所属父进程的各种资源。

并发是为了提高软件运行的效率,同时软件也必须要解决并发产生的问题。

下面是一个并发时出现问题的例子。在这个例子中,通过多线程同时对一个共享变量进行更新操作而产生了并发问题。最常见的并发例子就是多线程同时自行i++的示例,这里就不再过多介绍了。

持久化

因为内存中的数据是临时存在的。如果断电或系统崩溃,内存中的数据就会丢失。所以,我们需要在硬件和软件的共同作用下,将数据持久化存储。

众所周知,用于持久化数据的设备是磁盘。而在操作系统中管理磁盘的软件叫做文件系统(file system)。文件系统负责以高效和可靠的方式,将用户创建的任何文件存储在系统的磁盘上。 这里注意一点,操作系统中,存储和管理信息的基本单位是文件。

在持久化主题中,要研究的两方面的内容:一方面操作系统要提供给应用软件哪些API接口,以便应用软件可以完成创建爱你文件、写入文件以及关闭文件等类似的操作。另一方面,操作系统还要知道将写入的数据存在磁盘的什么位置,然后还需要按照文件系统所维护的各种结构来记录本次数据的相关信息

当然,还有性能方面的考虑,比如延迟写入磁盘,批量写入磁盘以及优化文件系统的数据结构等。

简单历史

手工操作阶段。

计算机最早的时候就是在纸带上进行打孔,来代表1和0。这个阶段就是人工把打孔好的纸带直接送入计算机运行。特点就是人工给计算机输入一条任务、一次只能运行一个任务。

批处理系统

在批处理系统阶段,首先由人工将任务批量的输入并保存到一个临时存储上,比如磁带。然后让一个程序(操作系统最早的雏形)开始自动从磁带上读取任务,依次输入给计算机进行执行。 这个阶段的特点就是多了一个自动读取任务的监控程序,也是操作系统的雏形。但计算机还是一次只能执行一个内容。

超越库函数:保护

这个阶段是操作系统这个软件开始对硬件资源进行管理,这时出现了系统调用的概念。这时操作系统对硬件的操作具有了特殊的权限,而应用软件则没有。应用软件想要对硬件资源进行使用必须通过操作系统,又操作系统决定如何分配硬件资源给应用程序。比如让应用程序使用哪段内存等。

多道程序系统

所谓多道程序系统,就是允许多个程序同时进入内存并运行,并允许他们交替在CPU上运行,他们共享计算机上的各种硬件、软件资源。当一道程序因I/O请求而暂停运行时,CPU便立即转去运行另一道程序。

现代操作系统

随着互联网的发展,要求操作系统能够支持网络,同时对安全性也提出了更高的要求。

《操作系统导论》学习笔记一:操作系统简介

下一章,我们给大家介绍操作系统是如何虚拟化CPU的。

欢迎关注 Go学堂 ,关注送《Go常见错误100例及原理解析》pdf文档。