几个概念

  1. CPU、虚拟CPU
  2. 进程
  3. 内存、虚拟地址空间

  • 物理的CPU被OS虚拟成了多个虚拟的CPU,这些虚拟CPU分别运行各自的程序,这些正在运行的程序被称为进程。
  • 物理内存被OS虚拟成了多个虚拟地址空间,每个进程都有独立的、自己的地址空间,程序的指令和数据都在地址空间中
  • 磁盘被OS虚拟化为文件系统,文件是被多个程序共享的,它并不是多个虚拟的磁盘,不过也不是无条件共享,涉及到例如互斥共享等多个问题,以后再谈。

1 Virtualizing the CPU

我们在Linux系统上运行C语言程序,体会一下虚拟化的意义。

Windows对多用户的支持不是很好,相关的系统API可能也没有,推荐适用Linux或Unix系统。

// cpu.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <assert.h>int main(int argc,int *argv[]){if(argc != 2){fprintf(stderr,"usage:cpu <string>\n");exit(1);}char *str = argv[1];for(int i = 0;i < 4;i++){sleep(1);printf("%s\n",str);}return 0;
}

这个程序很容易,需要运行的时候输入一个参数,比如一个字符,值得解释的是sleep(1),也就是让程序暂停1秒,这非常重要,这意味着物理的CPU在这1s时间可以不用执行该进程,转而执行其他进程。

注意,虚拟后的CPU,最终仍然要在真实物理CPU来执行,要想让每个进程都得到执行,那就应该以合理的方式让他们切换执行

我们先运行一个进程试试看,输入命令./cpu A1

打印了4个A1,并且是每隔1s打印一个,这与我们的预期相符。

接下来,我们同时运行多个进程试试看,输入命令./cpu A1 & ./cpu B2 & ./cpu C3 &

按照直观的理解,不应该是

A1
A1
A1
A1
B2
B2
B2
B2
C3
C3
C3
C3

不应该是这样吗?但是看起来这3个进程并不是顺序执行的,而是并发执行的,也就是它们趁着其他进程在sleep的时候,抢占了CPU去执行自己了(注意,我们假设计算机只有1个CPU,而且是单核的)。

这样一来,就出现了图中的乱序了。

我们也能充分的感受到,不要让物理CPU闲着的重要理念,同时我们也能想象到,多个进程同时执行,就会涉及到更多的问题,如果是之前的顺序执行,我们只需要进程1执行,其他等待–>进程1执行完成,进程2执行,其他等待–>进程2执行完成,进程3执行–>进程3执行完成。

也就是说,我们只需要等着一个程序执行完,再执行其他程序,这样很简单,但是效率非常低,比如,如果正在执行的程序不使用CPU,去“sleep”了,或者去找I/O设备“玩”了,CPU就只能呆着,其他程序也不能进来执行,CPU利用率很低


为了避免这种问题,现代OS都采用了类似多道批处理的技术,正在执行的程序不执行时,其他程序会进入CPU执行,而不会允许CPU空闲,要榨干CPU!

就如上面的程序,当一个进程sleep的时候,其他进程就会进入CPU执行,但是,具体如何执行,取决于OS的调度程序,取决于OS设计的策略,所以目前我们还不能得知它具体是如何运作的(也许你可以查看Linux内核,不过如果你有此能力,就不会看见这篇文章了)。

1.1 补充:实例中的C语言知识

以下请自学

1.1.1 main函数参数,argc和argv

1.1.2 fprintf()

1.1.3 sleep()

2 Virtualizing Memory

我们先上代码

// mem.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>int main(int argc,int *argv[]){int *p = malloc(sizeof(int));
//    assert(p != NULL);printf("(%d) memory address of p: %08x\n",getpid(),(unsigned)p);*p = 0;for(int i = 0;i < 4;i++){sleep(1);*p = *p + 1;printf("(%d) p: %d\n",getpid(),*p);}return 0;
}

运行程序./mem

运行多个进程:./mem & ./mem & ./mem &

这里,我们依然能够看到的是虚拟化CPU,不过,虚拟化内存在哪里呢?目前还看不出来,因为Linux默认是启动地址空间随机化的,这样会让系统更安全,不易受到攻击,不过为了展现虚拟化内存,我们应该关掉它。

输入命令sysctl -w kernel.randomize_va_space=0,再输入./mem & ./mem & ./mem &


我们可以看到,三个进程居然地址完全一样!按理说,1个地址只能对应1个进程,所以,你就能体会到虚拟地址空间的含义了,这并不是真实的物理地址,它会通过某种机制,映射到真实物理地址去。

3 Sharing Disk Information

还记得我们刚才的两个程序吗?他们同时启动了多个进程,并且,这几个进程是同一个程序,也就是说,同一个存储在磁盘的文件,被多次读取到了内存,这也就意味着,磁盘信息是可以被同时多次读取的,我们也可以说,这几个进程共享了一个磁盘文件


思考:为什么内存和CPU要虚拟化为多个,而磁盘却是共享的?

  • 进程是运行中的程序,它是“活的
  • 程序是静止在磁盘中的指令和数据,它是“死的”。

对于正在运行的进程来说,我们需要为其独立地分配一整套生态系统,保证它正常执行,并且每个程序运行时候的结果可能不同,所以,就虚拟地提供了CPU和地址空间,让它们是相互独立的;而对于静止的指令和数据来说,完全没有必要虚拟成多份,那反而是浪费空间,当然这是针对读取而言,写入还需要视情况,不过整体来说,读取信息是及其场景的,将磁盘设为共享也是合理的。


另外要谈的是,磁盘文件必须通过软件和硬件协作的方式,使其持久地保存,而不是很快就消失了,或者被其他数据覆盖掉了。

4 Concurrency

虚拟化对应的是进程,而并发对应的不仅仅是OS的进程,在OS之上的应用程序,也存在并发的问题,他就是多线程编程;虚拟化让一个CPU能并发地执行多个进程,而一个进程,也能并发地执行多个线程。

你一定知道多线程编程,是的,就是那个,我们现在重新审视一下它。

// threads.c

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>volatile int counter = 0;
int loops;void *worker(void *arg) {int i;for (i = 0; i < loops; i++) {counter++;}return NULL;
}int main(int argc, char *argv[]) {if (argc != 2) {fprintf(stderr, "usage: threads <value>\n");exit(1);}loops = atoi(argv[1]);pthread_t p1, p2;printf("Initial value : %d\n", counter);pthread_create(&p1, NULL, worker, NULL);pthread_create(&p2, NULL, worker, NULL);pthread_join(p1, NULL);pthread_join(p2, NULL);printf("Final value : %d\n", counter);return 0;
}

我们进行编译gcc threads.c -o threads -lpthread,注意,<pthread.h>不是Linux默认的库,编译链接需要加上参数-lpthread,也就是需要链接额外的Import Library:libpthread.a

我们进行测试:

对于输入的参数N,输出结果应该是2N(先知道事实,看不懂多线程程序没有关系),但是最后两个,当参数足够大,比如5亿的时候,结果就诡异了

这是由于计数器的值的更新不是原子操作,他需要:

  • 内存–>寄存器
  • 寄存器递增
  • 寄存器–>内存

3个步骤,但是,这几个步骤可能被其他操作打断,这就造成了结果的诡异。关于原子操作以后再说。

5 小结

我们谈了几件事儿

  • 物理CPU – 虚拟化CPU – 多进程并发
  • 物理内存 – 虚拟地址空间 – 进程独立地址空间
  • 磁盘(持久性) – 文件系统 – 共享磁盘信息
  • OS之上的并发:单个进程中的多线程

版权声明

本文是读书笔记,来自于书籍《Operating System:Three Easy Pieces》

【操作系统】虚拟化CPU、Memory,共享文件相关推荐

  1. 操作系统之虚拟化CPU(一)介绍

    但凡学习过计算机的人,一定都听说过一个问题,并发和并行的区别,此处引用知乎用户的关于吃饭的形象比喻,是的,你就是任劳任怨的CPU,而吃饭和接电话是你要执行的多个任务. 你吃饭吃到一半,电话来了,你一直 ...

  2. 操作系统基础-CPU虚拟化

    点击上方"小强的进阶之路",选择"星标"公众号 优质文章,及时送达 预计阅读时间: 13分钟 操作系统的三个要素 操作系统的定位是计算机资源(CPU,内存,硬盘 ...

  3. Intel X86_64 虚拟化CPU

    文章目录 前言 一.VMX 1.1 处理器是否支持VMX 1.2 CPU虚拟化 1.3 VMX 简介 二.VMCS 2.1 VMCS 2.2 VMCS data 2.3 VMCS launch sta ...

  4. 服务器虚拟化如何分配cpu,Hyper-V虚拟化CPU分配探讨

    开始之前,先看看物理机的CPU如何调度 我该为我的物理服务器分配多少虚拟CPU给虚机才合理,分配比1:1,2:1,听说还可以到8:1? 我的虚拟化CPU分配比达到4:1,会不会引起CPU资源过载? 我 ...

  5. linux:关于Linux系统中 CPU Memory IO Network的性能监测

    我们知道:系统优化是一项复杂.繁琐.长期的工作.通常监测的子系统有以下这些: CPU Memory IO Network 下面是常用的监测工具 Linux 系统包括很多子系统(包括刚刚介绍的CPU,M ...

  6. 老李分享:shell 监控cpu,memory,load average 1

    老李分享:shell 监控cpu,memory,load average poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课 ...

  7. 容器操作系统虚拟化_为什么操作系统在容器化世界中很重要

    容器操作系统虚拟化 Linux容器中运行的应用程序被隔离在物理服务器上运行的操作系统的单个副本中. 该方法与基于虚拟机管理程序的虚拟化形成对比,在虚拟机管理程序中,每个应用程序都绑定到来宾操作系统的完 ...

  8. 虚拟化服务器里的cpu是什么型号的,VMware虚拟化CPU型号不一样,在集群中如何进行VMotion?...

    VMware虚拟化CPU型号不一样,在集群中如何进行VMotion? 答案:开通EVC功能. EVC 是什么? EVC 是 Enhanced vMotion Compatibility 的简称.EVC ...

  9. 超线程cpu的寄存器_操作系统之CPU知识扫盲

    前言 CPU的英文全称是(Central Processing Unit),中文意思翻译中央处理器,是计算机的主要设备之一,功能主要是解释计算机指令以及处理计算机软件中的数据.计算机的可编程性主要是指 ...

最新文章

  1. 从Preact了解一个类React的框架是怎么实现的(一): 元素创建
  2. VC++ MSXML创建XML文件以及对XML文档解析
  3. 控件View动态设置高度时会卡顿、速度慢的情况解决
  4. linux修改时间指令,Linux 修改时间的指令
  5. 读《深入jvm原理》之class文件
  6. 简单说下COALESCE这个日常使用的函数
  7. 如何评价分类模型性能?(足球荔枝)
  8. 前端学习(2887):如何短时间内实现v-for proxy代理
  9. 生产环境linux下安装两个及两个以上tomcat实践
  10. Dailymotion 视频下载神器,喜欢太阳的后裔的人有福了!
  11. tail Linux 指令
  12. 软件开发 —— 过程资产与交付件
  13. wifi定位算法 java_机器学习在滴滴网络定位中的探索和实践
  14. OpenRefine数据清洗实战
  15. Android 即时通讯
  16. C语言 Mkl 矩阵乘法,MKL库矩阵乘法
  17. maven报错:Failure to transfer xxx.jar from xxx was cached in the local repository.
  18. 微信分享内容给朋友、朋友圈、QQ、QQ空间等
  19. git push时缺少Change-Id报错
  20. 遥信遥测遥控遥调四大概念介绍

热门文章

  1. Unity性能优化的N种武器
  2. Axis通过wsdd部署Web Service
  3. 自定义URL Scheme完全指南
  4. 大龄程序员怎样渡过中年危机?(转)
  5. QTP自传之web常用对象
  6. 控件中的Events个人理解。
  7. 本地执行php查看内存占用,查看页面执行php占用内存情况
  8. Mysql高级考试题_MySQL高级应用答案试题题目及答案,期末考试题库,章节测验答案...
  9. java默认值_Java中八种基本数据类型的默认值
  10. java stack list_JAVA自己实现List接口Stack