第四章 进程(Processes) 1.进程的组成和启动过程
进程的组成: 一个进程由两部分组成:1.进程内核对象 2.地址空间
进程的启动: 一个进程启动时系统会根据程序的类型调用相应的CRT Main函数 。如下表:
2.CRT Main执行的流程 具体流程如下,代码见 crtexe.c (1) 取得指向进程的命令行(command line)的指针 (2) 取得指向进程的环境变量的指针 (3) 初始化C/C++ Run Time的全局变量,这此变量放在StdLib.h中 (4) 初始化C Run Time 内存分配函数所用的堆,从而使malloc/free 函数可用。 (5) 调用程序中的静态变量和全局变量的构造函数 (6) 调用程序中的Main/WinMain函数 (7) 当从Main中返回后,取得Main的返回值Ret,调用C Run-Time exit(Ret) 函数,参数是Ret (8) 调用_onexit注册的函数 (9) 为所有全局和静态变量调用析构函数 (10) 若是Debug Build,如果_CRTDBG_LEAK_CHECK_DF 宏被设置了,系统会调用_CrtDumpMemoryLeaks函数 输出程序中的内存泄露的地方 (11) 以Ret参数调用操作系统的ExitProcess函数,操作系统会杀掉当前进程并设置进程的Exit Code. 注:第11条说明在Windows中主线程退出会执行ExitProcess,即使有未执行完的线程进程也会退出。这种做法与Linux不同。 若将ExitProcess改为ExitThread 那么主线程退出时 若还有其它线程在运行,进程不会退出。 3. 一个进程的实例句柄 (1)Handle/HMODULE/HINSTANCE Handle 是代表系统的内核对象,如文件句柄,线程句柄,进程句柄。 HMODULE 是代表应用程序载入的模块,win32系统下通常是被载入模块的线性地址。 HINSTANCE 在win32下与HMODULE是相同的东西,在Win32下还存在主要是因为win16 程序使用HINSTANCE来区别task。 HWND 是窗口句柄。。
他们之间代表不同的对像性质不同不能转换,主要是转换是没有意义的。 补充一点: 系统对内核对象以链表的形式进行管理,载入到内存中的每一个内核对象都有一个线性地址, 同时相对系统来说, 在串列中有一个索引位置, 这个索引位置就是内核对象的handle. HMODULE是一种特殊的handle他只对于exe, dll等模块
(2)进程的环境变量 环境初始值存储位置: 系统环境变量 HKEY_LOCAL_MACHINE"SYSTEM"CurrentControlSet"Control"Session Manager"Environment 用户环境变更 HKEY_CURRENT_USER"Environment
(3)创建进程 CreateProcess()函数可以创建一个进程,在创建进程时两个内核对象会被创建,一个是进程内核对象,一个是线程内核对象。
4. 结束进程(Terminating a Process) 四种结束进程的方法: (1) 从主线程的入口函数返回----------推荐此方法。 (2) 进程中的任一线程调用ExitProcess()----------避免使用该方法 (3) 其它进程中的任一线程调用TerminateProcess()----------避免使用该方法 (4) 进程中的所有线程执行完毕后, 进程会自动结束----------这种情况很少发生。
ExitProcess & ExitThread: 调用以上两个函数的线程会使线程或进程立刻退出,写在以上两个函数后面的代码永远都不可能被执行。如: ExitThread(0); Printf(“"nYou will never see this!”);
进程结束与资源释放 无论进程以何种方式结束, 正常退出或异常退出,系统会保证释放掉进程所占用及分配的任何资源,就好像进程从没运行过一样。也就是说进程结束后不会泄露任何资源。
5.子进程 子进程有自已的进程地址空间,它不依附于父进程而独立存在。即使父进程终止了 子进程仍可以运行。 除非父进程给子进程共享了某些数据或资源 否则子进程无法操作父进程的数据。
父进程在创建完子进程后 根据需要 适时调用CloseHandle()函数 关闭子进程的Thread句柄和Process句柄。否则父进程会一直持有子进程的Thread和Process句柄 从而导致系统无法释放子进程的Process和Thread所占用的资源。父进程也可以通过 WaitForSingleObject 函数等待子进程结束。然后再关闭Process 句柄。
分离的子进程 在创建完子进程后, 父进程不需要与子进程有任何交互或不需要等待子进程执行完后再继续做其它的事, 那么在创建完子进程可立刻关闭父进程所持有的子进程的Process句柄和Thread句柄,从而将子进程分离出来。
例子如下: PROCESS_INFORMATION pi; // Spawn the child process. BOOL fSuccess = CreateProcess(..., &pi); if (fSuccess) { // Allow the system to destroy the process & thread kernel // objects as soon as the child process terminates. CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } |
|