分类: WINDOWS
2010-04-29 15:14:54
进程和线程在字面上看起来颇为相近,两者又是息息相关的,所以往往给初学者造成混淆,其实从英文原文来看,进程(Process)和线程(Thread)是完全不同的。在开始介绍本章中的多线程和下一章中有关进程的内容之前,首先在这里介绍进程和线程的概念以及它们之间的联系。
进程是正在执行中的应用程序,磁盘上存储的可执行文件只能称之为文件而不能称为进程,内存中正在执行的文件才叫做进程。一个进程是一个执行中的文件使用资源的总和,包括虚拟地址空间、代码、数据、对象句柄、环境变量和执行单元等。当一个应用程序同时被多次执行时,产生的是多个进程,因为虽然它们由同一个文件执行而来,但是它们的地址空间等资源是互相隔离的,这与不同文件在执行的情况是一样的。
进程是不“活泼”的,要使进程中的代码被真正运行起来,它必须拥有在这个环境中运行代码的“执行单元”,这就是线程,线程是操作系统分配处理器时间的基本单位,一个线程可以看成是一个执行单元,它负责执行包含在进程地址空间中的代码。当一个进程被建立的时候,操作系统会自动为它建立一个线程,这个线程从程序指定的入口地址开始执行(对于Win32汇编,就是源代码最后start指定的入口地址),通常把这个线程称为主线程,当主线程执行完最后一句代码的时候,进程也就没有继续存在的理由了,这时操作系统会撤销进程拥有的地址空间和其他资源,对我们来说,这就意味着程序的终止。
在主线程中,程序可以继续建立多个线程来“同时”执行进程地址空间中的代码,这些线程被称为子线程。操作系统为每个线程保存单独的寄存器环境和单独的堆栈,但是它们共享进程的地址空间、对象句柄、代码和数据等其他资源,它们可以执行相同的代码,可以对相同的数据进行操作,也可以使用相同的句柄。读者可以把一个进程中的多个线程看成是进程范围内的“多任务”。
进程和线程的关系可以看做是“容器”和“内容物”的关系,进程是线程的容器,线程总是在某个进程的环境中被创建,它不可以脱离进程单独存在,而且线程的整个生命周期都存在于进程中,如果进程被结束,其中的线程也就自然结束了。
系统中可以同时存在多个进程,每个进程中同时又可以有多个线程在执行,为了使所有进程中的线程都能够“同时”运行,操作系统为每个线程轮流分配时间片,当轮到一个线程执行的时候,系统将线程的寄存器值恢复回去并开始执行,当时间片结束的时候,系统打断线程的执行,将线程当前的寄存器环境保存下来并切换到另一个线程中去执行,如此循环。当切换到的线程和上一个时间片的线程并不属于同一个进程的时候,操作系统同时切换物理内存到线性地址空间的映射关系,这样线程存取的就是自己所属的进程中的代码和数据。
对于单处理器的计算机来说,不同线程实际上是在轮流使用同一个处理器,一个程序的运行速度并不会因为建立多个线程而加快,因为线程多了以后每个线程等待的时间也就越长,但是对安装了多个处理器的计算机来说,操作系统可以将不同的线程安排到不同的处理器中去执行,这样一个进程中的多个线程就会真正获得多个时间片而加快整个进程的运行速度。当然这个过程还需要操作系统的支持。Windows 9x系统不支持多处理器,即使系统中安装有多个处理器,所有线程还是被安排在同一个处理器上运行,其他的处理器则处于空闲状态。Windows NT系统支持多处理器。
3. 线程环境
在第12章中已经提到过,Windows为不同的线程循环分配时间片,当挂起一个线程的时候,为了以后能够将它恢复执行,系统必须首先将线程的运行环境保存下来,当线程在下一个时间片恢复执行时,将运行环境恢复回去,线程就不会感觉到自己被打断过,这就像甲外出的时候把办公室交给乙管,不管乙把办公室搞成什么样子,只要在甲回来之前把所有东西恢复原状,甲就不会意识到甲出去的时候办公室被挪做它用了。
线程环境就是这个道理,Windows中将线程环境称为“Thread Context”(注意:没有进程Context,因为进程是不活动的),对一个线程来说,只要所有的寄存器没有改变,环境就没有改变,所以线程环境实际上就是寄存器的状态,它可以用一个CONTEXT结构来表示。
结构定义为:
CONTEXT STRUCT
ContextFlags DWORD ?
iDr0 DWORD ?
iDr1 DWORD ?
iDr2 DWORD ?
iDr3 DWORD ?
iDr6 DWORD ?
iDr7 DWORD ?
FloatSave FLOATING_SAVE_AREA <>
regGs DWORD ?
regFs DWORD ?
regEs DWORD ?
regDs DWORD ?
regEdi DWORD ?
regEsi DWORD ?
regEbx DWORD ?
regEdx DWORD ?
regEcx DWORD ?
regEax DWORD ?
regEbp DWORD ?
regEip DWORD ?
regCs DWORD ?
regFlag DWORD ?
regEsp DWORD ?
regSs DWORD ?
ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?)
CONTEXT ENDS
结构中的字段包括80x86系列处理器中的全部寄存器,其中FloatSave字段用来保存浮点寄存器的内容,ExtendedRegisters字段用来保存扩展寄存器的内容(如MMX寄存器等),ContextFlags字段是供结构自己用的标志。
CONTEXT结构是Windows中惟一与硬件平台相关的结构,因为Windows设计成可以在不同的硬件平台上运行,当运行于MIPS,Alpha和PowerPC等平台上时,显然寄存器名称就和80x86系列的不同了,这时CONTEXT结构的定义也相应改变了。
在线程处于休眠状态的时候,它的线程环境由Windows保存,可以通过API获取它们并修改它们,当线程分配到时间片恢复运行时,Windows将修改过的线程环境恢复回去,而线程并不会意识到环境已经被修改了。用这种方法可以修改regEip字段,让某个线程转移到其他地方执行。