内核对象
概念:每个内核对象只是内核分配的一个内存块,并且只能由该内核访问。该内存块是一种数据结构,它的成员负责维护该对象的各种信息。有些数据成员(如安全性描述符、使用计数等)在所有对象类型中是相同的,但大多数数据成员属于特定的对象类型。例如,进程对象有一个进程I D、一个基本优先级和一个退出代码,而文件对象则拥有一个字节位移、一个共享模式和一个打开模式。
创建: CreateThread, CreateFile, CreateFileMapping, CreateSemaphore
关闭: CloseHandle
共享:
为什么共享?
许多情况下,在不同进程中运行的线程需要共享内核对象。下面是为何需要共享的原因:
• 文件映射对象使你能够在同一台机器上运行的两个进程之间共享数据块。
• 邮箱和指定的管道使得应用程序能够在连网的不同机器上运行的进程之间发送数据块。
• 互斥对象、信标和事件使得不同进程中的线程能够同步它们的连续运行,这与一个应用程序在完成某项任务时需要将情况通知另一个应用程序的情况相同。
共享的方法:
1. 对象句柄的继承性
2. 改变句柄的标志:HANDLE_FLAG_INHERIT, HANDLE_FLAG_PROTECT_FROM_CLOSE
3. 命名对象:CreateMutex, CreateEvent, CreateSemaphore, CreateJobObject, CreateFileMapping, CreateWaitableTimer, Open*
4. 终端服务器的名字空间
5. 复制对象句柄 DuplicateHandle
进程
概念:一个正在运行的程序的实例,由内核对象和地址空间两部分组成。每个进程至少拥有一个线程,来执行进程的地址空间中的代码。
进程的实例句柄:GetModuleHandle函数返回可执行文件或DLL文件加载到进程的地址空间时所用的句柄/基地址
进程的命令行(解析及释放命令行参数数组的内存):PWSTR* ppArgv = CommandLineToArgW(GetCommandLineW(), &nNumArgs); HeapFree(GetProcessHeap(), 0, ppArgv);
环境变量:子进程获得它自己的父进程的环境块拷贝,子进程与父进程并不共享相同的环境块
终止进程的运行:
-
•主线程的进入点函数返回(最好使用这个方法)。(该线程创建的任何C + +对象将能使用它们的析构函数正确地撤消;作系统将能正确地释放该线程的堆栈使用的内存;统将进程的退出代码(在进程的内核对象中维护)设置为进入点函数的返回值;统将进程内核对象的返回值递减1)
-
进程中的一个线程调用ExitProcess函数(应该避免使用这种方法)。(显式调用ExitProcess和ExitThread是导致应用程序不能正确地将自己清除的常见原因。在调用ExitThread时,进程将继续运行,但是可能会泄漏内存或其他资源。)
-
另一个进程中的线程调用TerminateProcess函数(应该避免使用这种方法)。(TerminateProcess函数是个异步运行的函数,也就是说,它会告诉系统,你想要进程终止运行,但是当函数返回时,你无法保证该进程已经终止运行。因此,如果想要确切地了解进程是否已经终止运行,必须调用WaitFroSingleObject函数或者类似的函数,并传递进程的句柄。)
-
进程中的所有线程自行终止运行(这种情况几乎从未发生)。
线程的基础知识
线程由内核对象和线程堆栈组成。
进程只是线程的容器。
创建线程:
- 主线程的进入点函数的名字必须是main、wmain、WinMain、wWinMain,与这些函数不同的是,线程函数可以使用任何名字
- 线程函数必须返回一个值,它将成为该线程的退出代码。
- 线程函数(实际上是你的所有函数)应该尽可能使用函数参数和局部变量。