查看原文
其他

程序?进程?傻傻分不清

码农的荒岛求生 码农的荒岛求生 2020-12-18


操作系统基础篇:程序?进程?傻傻分不清



本节是操作系统系列教程的第二篇文章,属于操作系统第一章即基础篇,在真正开始操作系统相关章节前在这一部分回顾一些重要的主题,算是温故知新吧,以下是正文。


到目前为止,你肯定已经见过很多次这两个词了,“程序”“进程”。那程序和进程到底有什么区别呢。

程序是一个静态的概念。

进程是一个动态的概念。

我们用一个例子来形象的讲解一下这个区别。程序其实本质上和我们的菜谱非常类似,一个菜谱规定了完成一道菜的整个流程,一步一步每个节点执行什么样的操作,但是看一遍菜谱是不能变出一道美味可口的菜肴的。要想真正做出一道菜就应该按照菜谱的要求走一遍,准备好食材,按照菜谱的指导,打开燃气,锅热后倒入油,待油温适宜后放入准备好的食材、调味料,然后不断翻炒直至炒熟,这样一道美味就新鲜出锅啦。

在这个例子中如果把菜谱比作我们写的程序,那么按照菜谱真正炒菜的这个过程才是进程。如果你自己真的炒过菜,相信会对此有更加深刻地的理解,如果你还没有做过菜,那么笔者强烈建议读者自己真正的去炒一道菜感受一下。

进程是计算机科学当中一个及其重要的概念,彻底理解进程是理解操作系统工作原理的关键所在,同时也是编程高手的标志之一。



编程高手与普通程序员的分水岭


进程是计算机操作系统中至关重要的一个概念,可以说彻底理解进程这个概念是能否成为拥有“自我探索”能力的编程高手的一个分水岭,能彻底理解操作系统如何实现进程是编程高手的关键性标志。理解了这个概念以后你几乎不会再遇到程序出现了问题,但是你根本就不知道到底哪里出现问题的窘境。正因为这个概念的重要性因此我们后面的文章会有很大一部分都是围绕着进程来进行讲解的,目的就是确保大家能真正掌握这一思想,从而在成为高手的道路上迈出坚实的一步。


接下来让我们首先来看一下程序是如何生成的。



程序是如何生成的


程序这个词其实是比较笼统的,在我们学习工作工作过程中,即指我们人类可以认识的字符串程序,也可以指机器可以运行的二进制机器指令程序,这个程序就是可执行程序。


所以在这里需要大家能意识到一点,程序这个词有两种含义:

  • 人类可以认识的程序,这些程序就是用比如C/C++,Java,Python语言写成的文本文件。比如helloworld.c,hellworld.java,helloworld.py

  • 机器可以认识的程序,这些程序就是可执行程序。Windows下就是exe程序,Linux下就是elf程序。


因为计算机看不懂人类可以认识的文本文件程序,因此需要将文本文件程序转换为机器可以认识的可执行程序。这个翻译过程就是编译器来完成的。编译器将文本文件程序翻译成二进制机器指令程序。


在前几节中,有两种类型的语言,一类是C/C++这种编译型语言,一类是比如Python、Java等解释型语言,CPU可以直接运行C/C++程序经编译后生成的机器指令,但解释型语言不能直接被CPU执行,解释型语言是被解释器直接执行的,而解释器可以被CPU直接执行,因为这些解释器通常都是C/C++语言编写的,就好比下面这样:

$ python helloworld.py

其中python就是一个C语言程序,只不过这个C语言程序可以来执行python程序。有了这些背景后,接下来我们重点关注C/C++这类解释型语言是如何从文本文件转变为可执行文件的。


接下来的这句话,大家一定要理解,那就是:

   “程序其实包含两部分内容,一部分是指令(代码),另一部分是数据


有的同学可能会问了,程序里面不都是“指令(代码)”吗,不是的,大家一定要意识到这一点,非常重要。程序中不都是指令(代码),还包括数据。


比如 int a = 100; 这段代码在生成的可执行程序中是没有对应的机器指令的,为什么,因为这是数据。那么什么样的代码才有对应的可执行程序呢?比如if... while... +-*/,return等语句才会有对应的机器指令。


现在你应该清楚了吧,一般来说,对数据的操作部分我们都可以认为是指令,而除此之外的定义都是数据。


有了这些知识,你就能理解编译器啦,编译器的工作就是把C程序中的对数据的操作部分翻译成二进制机器指令,这些指令统一放在二进制文件中的一部分,这一部分就叫代码段,然后编译器收集C程序中定义的数据,把这些数据统一放在二进制文件中的另一部分,这一部分就叫数据段,就好比披萨一样分为两层,一个可执行文件就如下图所示:



这就是为什么最终可执行文件中有两部分的原因,这也是可执行程序在磁盘中的看起来是样子的。

这里需要大家意识到的一点就是可执行程序也是一个保存在磁盘上的普通文件,和我们的经常使用的文本文件没有本质的区别。

我们来总结一下,编译器将源代码分成两类,一类是对数据的操作,这一部分就被编译器翻译成了机器指令;另一类是数据,这些数据被编译器收集后放到了可执行文件的数据段。

可执行程序也是文件,和普通的文本文件没有什么本质的区别,只不过文本文件中保存的是人类认识的字符,而可执行程序保存的是机器指令以及机器指令操作的数据,这些二进制的指令或数据人类是很难直观理解的,但是CPU不一样,CPU可以直接执行这些二进制机器指令。

现在你应该清楚程序是如何生成的了吧,程序是编译器翻译而成的,可执行程序和普通文件一样,生成后被安静的保存在磁盘上。

从这里我们也可以看出程序其实和菜谱一样是一个静态的概念。程序被保存在磁盘上,只要磁盘没被破坏程序就可以一直被保存下去。

接下来让我们看看进程是怎么来的。



进程是如何生成的

到目前为止,保存在磁盘上的可执行程序和操作系统还没有半毛钱关系。如果一个程序仅仅是放在磁盘上除了占用磁盘控制之外其实是没有任何用处的,只有程序运行起来才能真正发挥它的作用。

那么程序是如何被运行起来的呢?

这点大家应该都非常熟悉,在Windows中我们通过双击程序图标,在Linux下直接键入程序的名字。但是这个回答大家可能并不满意,因为计算机的角度上看我们依然不清楚程序是如何运行起来的。

要回答这个问题,就需要我们的主角登场了,这里的主角就是操作系统。

我们的程序实际上是被操作系统运行起来的,大体经过了以下几个阶段。

1,当我们双击程序图标或者键入程序名字后,操作系统根据程序的名字去磁盘中找到可执行程序。

2,操作系统在内存为即将要运行的程序划出一块区域。

3,操作系统将找到的可执行程序从磁盘中copy到刚刚划分出的内存区域当中。

4,操作系统在内存中找到可执行程序代码段的起始位置,假设这个地址是A。

5,操作系统告诉CPU从A这个位置开始执行。

经过了这几个步骤后,CPU就开始运行我们的程序啦。值得注意的是以上只简化后的几个重要步骤,实际情况要更加复杂,但是这个简化的步骤已经足以让我们理解操作系统是如何来运行程序的了。在后面的文章中我们会详细描述这一过程。所以你会看到当打开一个比较大的程序,比如游戏时,总是非常慢,还会给出“正在加载”的提示,其实就是操作系统在忙着以上几个步骤。

在这里,我们可以给出进程的定义了。

程序运行起来之后就叫进程。

而进程也是我们后面文章的重中之重。

进程是操作系统精心构筑的一个概念,理解进程对理解操作系统来说至关重要,同时深刻理解进程也是编程高手和普通程序员的分水岭。



总结

在这一节中我们重点关注了程序和进程这两个概念。

程序是静态的,放在磁盘上的,保存了程序的指令和数据普通文件。

进程是动态的,存防在内存中的,CPU执行程序时的样子。

只要磁盘没有被破坏,程序就可以永久保存。

而进程一旦在内存中被CPU执行完毕,操作系统就会回收进程占据的所有内存空间,进程的生命周期取决于程序的运行时间。

程序需要存放在磁盘上,占用的是磁盘的空间。

而进程需要在内存中被运行,占用的是内存空间。

通过本节,希望大家能清楚的理解程序和进程这两个概念。

欢这篇

就点下在看哦


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存