进程的组成:
进程内核对象和地址空间。
借用这个图来说明一下,虽然是linux的,但基本一样。进程的4G空间,2G是给操作系统使用的,2G是给进程本身使用。操作系统的2G内存在所有进程中是共享的,它们映射到同样的地址(好像不对,不是完全共享的)。
主线程:
系统创建一个进程时候,会自动为进程创建第一个线程,该线程称为主线程。
进程的生命过程:(几个重要的函数)
启动函数 -> 入口点函数 -> exit函数。
(1) 启动函数:
启动函数将完成以下初始化工作:
l 获取指向新进程完整命令行的一个指针。
l 获取指向新进程环境变量的一个指针。
l 初始化C/C++运行库的全局变量。
l 初始化内存分配函数malloc和其他底层I/O例程使用的堆。
l 调用全局和静态C++对象的构造函数。
(2) 入口点函数:
完成初始化工作后,启动函数就会调用应用程序的入口点函数。
Int _tmain( int argc, TCHAR *argv[], TCHAR *envp[] ):
argc: 命令行数组的长度;
argv: 命令行数组(可通过GetCommandLine函数来获取完整命令行);
envp: 环境变量。
(3) Exit函数:
入口点函数返回后,启动函数将调用exit函数。
exit函数执行以下任务:
l 调用_onexit函数调用所注册的任何一个函数。
l 调用全局和静态对象的析构函数。
l 在DEBUG生成中,生成内存泄漏报告。
l 调用ExitProcess函数“杀死”进程,并设置退出代码。
创建进程:
CreateProcess()函数的参数:
(1) pszApplicationName:
可执行文件的路径名(可使用绝对路径或相对路径,其中,文件名必须指定扩展名,如.exe)。
(2) pszCommandLine:
命令行。命令行是一个字符串数组,一般第一个标记存放可执行文件的名称,当pszApplicationName传入NULL时,系统便会通过该标记来定位可执行文件。使用命令行标记的文件名称来查找文件时,如果不指明扩展名,会默认是.exe的扩展名。CreateProcess还会按照以下顺序搜索可执行文件:
l 主调进程.exe文件所在的目录。
l 主调进程的当前目录。
l Windows系统目录,即GetSystemDirectory返回的System32 子文件夹。
l Windows目录。
l PATH环境变量列出的目录。
(3) fdwCreate:
该参数表示了影响新进程创建方式的标志。(例如,CREATE_SUSPEND标志,让系统创建新进程的同时挂起其主线程,这样父进程就有充足的时间修改子进程的属性)fdwCreate参数还允许我们制定进程的优先级类。
(4) ppiProcInfo:
指向一个PROCESS_INFORMATION结构,其中包含进程及其主线程的id。
GetCurrentProcessId:得到当前进程ID;
GetCurrentThreadId:得到当前线程ID;
GetProcessId:获得指定句柄对应的进程ID;
GetThreadId:获得制定句柄对应的线程ID;
GetProcessIdOfThread:获得线程所属进程的ID。
终止进程:
ExitProcess和TerminateProcess函数。它们的区别如下表所示:
函数 |
参数 |
调用者 |
实时性 |
推荐 |
ExitProcess |
无 |
被终止的进程本身 |
实时 |
否 |
TerminateProcess |
被终止的进程句柄 |
任何进程 |
非实时 |
否 |
(注:实时性,表示该函数调用完毕时,是否保证该进程已经被强行终止了)
虽然以上函数都能实现对进程的终止,但我们并不推荐使用它们来终止一个进程,而更倾向于让进程自动退出。原因是使用以上两个函数终止进程,虽然操作系统的资源被释放了,但由于没有正常调用exit函数,因此C/C++运行库的资源并不能得到正常清理。
进程退出时,会依次执行以下操作:
(1) 终止进程中遗留的线程。
(2) 释放进程分配的所有用户对象和GDI对象,并关闭内核对象句柄。
(3) 设置退出代码(进程未退出时,该值为STILL_ACTIVE),进程的退出代码是最后退出的那个线程的退出代码。可通过GetExitCodeProcess获取该值。
(4) 进程内核对象的状态编程已触发状态。
(5) 进程内核对象使用计数减1
子进程:
一个进程可以生成一个新的进程来帮助完成工作,该新进程称为子进程。父进程可以创建一个子进程,并等待它结束,再继续工作;也可以让子进程独立运行,而不管它什么时候结束。
进程的权限:
要提升进程的权限,只能在进程启动之前进行,一旦进程启动完毕,将无法改变权限。一个可执行文件(如.exe)的.manifest(清单)文件中就存放了包括权限在内的信息,它可以作为一个后缀名为.manifest的文件单独存在,也可以嵌套在.exe文件中(假如可执行文件已经嵌入了清单,则外部的清单文件将被忽略)。
作业:
作业是将进程组合在一起工作的一个“沙箱”,它用来限制和管理进程的工作。(作业和进程的关系,有点类似进程与线程的关系。当然,这只是个比喻,二者之间还是有不少差别的)