一、基本概念<?xml:namespace prefix = o />
1、线程是CPU的调度单位。
2、核心对象(kernel object)是系统的一种资源,系统对象一旦产生,任何应用程序都可以开启并使用该对象。系统给予核心对象一个计数值作为管理之用。
前三者用于线程的同步,file-mapping用于内存映射文件。这些核心对象的产生方式不同,但都会获得一个handle作为识别,每次被使用,对应的计数值加1,结束的方式则相当一致,调用CloseHandle。
“进程对象”并不是用来执行程序代码,程序代码的执行是线程的工作,“进程对象”只是一个数据结构,系统用它来管理进程。
3、进程的生命周期
我们双击程序图标执行程序,其实就是shell调用CreateProcess来激活一个进程,流程如下:
1)Shell调用CreateProcess激活XXX.exe。
2)系统产生一个“进程核心对象”,计数值为1。
3)系统为此进程建立一个4GB地址空间。
4)加载器将必要的代码加载到上述地址空间中,包括程序,数据,以及所需的动态链接库。这些动态链接库被记录在可执行文件(PE文件格式)的.data section中。
5)系统为此行程建立一个线程,称为主线程。线程才是CPU时间分配的对象
6)系统调用C runtime函数库的Startup Code。
7)Startup Code调用.exe程序的WinMain函数。
8)应用程序开始运行。
9)使用者关闭应用程序,使WinMain中的消息循环结束掉。
10)回到Startup code
11)回到系统,系统调用ExitProcess结束进程
可以说,通过这种方式执行起来的所有Windows程序都使Shell的子进程,本来母进程与子进程之间可以有某些关系存在,但shell调用CreateProcess时已经把母子间的脐带剪断了。
如果一个进程想结束自己的生命,可以调用:
VOID ExitProcess(UINT fuExitCode);
如果一个进程想结束其他进程的生命,可以使用;
BOOL TerminateProcess(HANDLE hProcess, UINT fuExitCode);
TerminateProcess一般不建议使用。因为一般进程结束时,系统会通知该进程所开启的所有DLL,如果以TerminateProcess结束一个进程,系统不会做这件事,这并不是我们希望的。
4、线程的生命周期
执行程序代码,是线程的工作。当一个进程建立后,主线程也产生了,我们可以调用CreateThread产生额外的线程,系统会帮我们做如下事情:
1)配置“线程对象”,其handle将成为CreateHandle的返回值
2)设定技计数值为1
3)配置线程的context
4)保留线程的堆栈
5)将context中的堆栈指针和指令指针设定好
所谓工作切换就是对线程context的切换。
线程之间不必考虑控制权释放的问题,因为Win32操作系统的特点是强制性多任务的。
线程的结束一种是正常退出结束;另一种是通过ExitThread(做善后工作);或别的线程通过TerminateThread将它终结掉;当然进程结束,线程也就结束了。
还可以以_beginthreadex取代CreateThread。
关于线程优先线论述,可以参见[1,P44].。
参考
[1] 深入浅出MFC