您的位置:首页 > 其它

关于指令、数据、程序和进程的一些思考

2015-12-13 19:32 453 查看
转载请注明来源:/article/7734849.html

从动态链接库说起

关于指令和数据的思考实际上是从写一个汇编语言课设开始的,当时要在Windows下写一个截获键盘操作的win32程序,老师推荐了一本《Windows环境下32位汇编语言程序设计》。(实际上这个课设就是这本书上的一个例子)

截获键盘操作就是要靠钩子函数,而使用钩子函数必须使用动态链接库。关于动态链接库,《设计》中有如下叙述:

如果有多个程序用到同一个动态链接库,Windows在物理内存中只保留一份库的代码,仅通过分页机制将这份代码映射到不同进程的地址空间中,这样不管有多少程序在使用一个库,库代码实际占用的物理内存永远只有一份。

……

有一个最重要的概念一定要牢记:动态链接库是被映射到其他应用程序的地址空间中执行的,它和应用程序可以看成是“一体”的,动态链接库可以使用应用程序的资源,它所拥有的资源也可以被应用程序使用,它的任何操作都是代表应用程序进行的,当动态链接库进行打开文件、分配内存和创建窗口等操作后,这些文件、内存和创建窗口等操作后,这些文件、内存和窗口都是为应用程序所拥有的。

由于当时并没有学习操作系统等相关的知识,头脑中也没有进程的概念,那时我就想不明白,多个程序如何共享同一段内存中的指令:万一程序A也执行这段指令,程序B也执行这段指令,执行不会乱套吗?数据不会混在一起吗?我做了如下批注,“多个程序在同一时刻同时执行该代码怎么办?”

当时急于赶作业,也没有往下深究,直到最近看CSAPP看到了链接一章,才又想起这个问题,由于已经在学操作系统了,我就来把我的思考分享一下。

进程

先来说说什么是进程。进程并不是程序,程序只是一些存储在磁盘上的指令和数据。当需要执行这个程序时,操作系统就要创建一个进程,形成该进程的进程控制块(Process Control Block,PCB),这个进程控制块记录了这个进程的许多信息,比如进程标识符,进程状态、CPU现场保护区、占有资源清单等。然后操作系统把程序的指令和数据加载到指定的内存区域,一个进程就形成了。即进程就是一个运行着的程序,它占用着诸如内存、IO设备之类的资源,包含了加载到内存中的程序的指令和数据,以及进程控制块。

进程有着它的状态,可能正在运行着,可能等待着把数据从硬盘到内存加载完成,也可能因为CPU正在运行其他进程的指令而不得不等一会。CPU现场保护区也是一个很重要的东西,当一个进程由于某种原因变成非运行状态时,操作系统就会将一些信息保存到这里,比如通用寄存器、程序计数器和状态寄存器等。

思考

好,现在回到一开始所说的动态链接库,我们来看看为什么只保存一份代码也能让多个进程无冲突地运行着。动态链接库的代码映射到进程的地址空间,即逻辑上变成这个进程中的指令的一部分。它可能同时映射到了多个进程的地址空间中,这些进程在某一个时刻只有一个在运行着。当某个进程执行到动态链接库的指令时,CPU一条条将指令加载到指令寄存器,然后CPU根据这些指令进行使用资源(比如push、pop、in、out),进行计算(比如add、sub、mlu、div)等操作,然后将中间结果存到寄存器中。如果进行到一半,这个进程的时间片用光了,那操作系统就将CPU现场保存下来,将另一个进程的CPU现场恢复,然后将控制转移至新的进程,它也可以将动态链接库中的指令加载到指令寄存器中,然后利用自己的数据以及CPU现场进行各种操作。然后可能时间片使用完毕,保存CPU现场,加载另一个进程的CPU现场。就在这CPU现场保存和恢复的过程中,进程间就不存在任何干扰了。最重要的是,CPU现场信息并不属于某段指令,它归进程所有。指令只是在指挥CPU怎样使用这些数据(很可能对不同的数据有不同的指挥),然后将中间数据保存在CPU或栈中,新的指令可以继续指挥CPU使用这些中间数据,得到最终结果后将结果以某种方式输出。

总结

我们可以将计算机计算的过程比作炒菜:指令是菜谱,数据是食材,CPU就是你,当然还有寄存器就是锅碗瓢盆,各种资源比如保温箱。你要根据菜谱来处理食材,处理到一定程度先放到碗里,然后处理别的食材,最后把它们合到一起处理,全部处理完就可以上桌了。不同的菜可能有些处理步骤是相同的,比如如何将葱炒香,你为了节约纸张,就单独把它印了出来,放到菜谱第xx页,然后哪道菜菜谱需要写如何将葱炒香的地方就写个具体过程见xx页就可以了。你可能一个菜做一半需要将食材煮半个小时,你不能只等着煮好啊,你就将这道菜其他处理到一般的食材放到保温箱里,腾出碗来先炒别的菜。可能上道菜有将葱花炒香的过程,这道菜还有,这并不影响,你还可以再看。上道菜的食材煮好了,把碗里东西放进保温箱,取出上道菜其他的中间食材,然后从菜谱刚才的地方开始接着处理。

现在想想,当时我的想法犯了以下错误:1)对于单核CPU根本不存在所谓的“同时执行”的情况,不考虑流水线的话,CPU中每个时刻只有一条指令在执行。所以不可能两个进程同时读取这一条指令。2)进程的数据以及中间计算结果是进程私有的(共享数据除外),即使多个进程并发运行,操作系统也会在进程切换时维护这些进程私有的数据,而不会让一个进程访问或修改了另一个进程的数据(即使在它们执行同一段指令)。

转载请注明来源:/article/7734849.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: