进程
进程是一个程序正在运行的实例,是操作系统分配资源基本单位,包括两点:
1.一个内核对象,操作系统用来管理进程。内核对象也是系统保存进程统计信息的地方。
2.一个地址空间,包括所有可执行文件和dll的数据。此外还包含动态内存分配,比如线程堆栈和堆的分配。
进程是有惰性的,只提供了空间和数据,要做任何事情,都需要一个线程在它的上下文(CONTEXT)中运行。线程负责执行代码,一个进程可以有多个线程,进程创建时,系统会自动创建一个主线程,从main函数进入。
单CPU下,CPU采用轮询方式为每个线程分配时间片,造成所有线程同时进行的假象。
创建进程
一个线程调用BOOL CreateProcess(。。。。)创建一个进程时,创建成功后返回TRUE。创建进行以下操作:
1.系统创建一个进程内核对象,初始使用计数为1。进程内核对象不是进程本身,是系统用来管理这个进程的一个小型数据结构对象。
2.系统为进程创建一个虚拟地址空间,将可执行文件和dll加载进去。
3.创建一个主线程,入口可能是WinMain,wWinMain,main,wmain,这是由连接器设置的。
线程
前面说线程是进程中干事的选手,是cpu任务调度的基本单位,包括:
1.一个内核对象,系统用来管理线程;
2.一个线程栈,用于维护线程执行时所需的所有函数参数和局部变量。
线程操作:
创建:调用HANDLE CreateThread(…),当然实际使用中要尽量使用_beginThreadex()函数,因为后者会为创建的线程分配一个tiddata数据结构,用于保存线程异常时的状态;而前者,异常时,会改变全局变量,比如errno。
挂起与恢复:挂起:susPendThread(…),让线程变成不可调度,即不分配CPU时间片;恢复:resumeThread(…),让现场恢复可调度状态。
……
线程内部结构:
线程内核对象由上下文(CONTEXT)、其他特性和统计信息构成,上下文保存线程上一次执行时,线程得CPU寄存器状态。例如单CPU线程A切换到B,会进行:
1.CPU寄存器内容保存到线程A得上下文;
2.线程B得上下文加载到CPU寄存器。
其他特性和统计信息记录着该线程对象的信息,比如使用计数。。。
线程栈保存着线程里的临时变量、函数参数等,它由系统创建并且预定默认1MB的地址空间并调拨两个页面储存器(预定是在虚拟内存种预定内存,不会占用物理储存器;给预定内存调拨才会使用物理存储器)。刚创建线程时,线程栈图如下:
随着预定内存(存在于虚拟内存)的使用,系统会不断为预定内存调拨物理储存器,但永远不会为最后一页调拨:
当访问到最后一页时,会发生抛出EXCEPTION_STACK_OVERFLOW异常。(想想无限递归= =)