WINDOWS核心编程——进程和作业

要理解进程首先要厘清下概念。进程是程序可执行文件在系统中运行的实例。进程是被系统所管理的资源的集合,cpu计算资源也是一种资源被用于执行代码所生成的指令,cpu执行指令流的最小单位就是线程,一个进程中必然含有一个线程。

main函数被称为入口函数,指定了进程进入我们所设计的流程位置,即当指令流执行到main函数代码所生成的指令时就进入到我们(用代码)设计的流程中。故main函数被称为入口函数而非启动函数,在程序连接生成可执行文件时,连接器连接了系统指定的流程,在流程中调用main函数,而在进入main函数之前会执行许多必要的初始化操作,并在main函数返回之后也会执行许多清理的动作确保进程中的资源被释放而不会发生泄漏。普通进程在入口函数前后的工作如下:


初始化了许多全局函数,虽然可以直接访问,当微软建议通过API如GetCommandLine、GetEnvironment*、Get/SetCurrentDirectory来访问它们:


对于不同的子系统(subsystem)而言,连接器所指定的入口函数并不相同。对于GUI程序而言的入口函数被指定为WinMain函数,第一个参数为进程句柄事实上指定的是WinMain函数在进程空间中的地址,许多资源需要通过这个地址作为参数调用API获得。入口地址可以在程序中也可以通过调用GetModuleHandle获得,当GetModuleHandle参数为NULL时获得的是进程的基地址,当是DLL的名称时为DLL的基地址,作用范围为当前进程通过GetModuleHandle是无法获得其他进程的基地址的,并对于DLL而言也必须是已经加载的DLL(位加载的DLL并不属于当前进程)。

除了通过系统启动一个进程之外,我们还可以在进程中启动另外一个进程(子进程,启动之后就脱离关系了),使用如下函数:

BOOL CreateProcess
(
  LPCTSTR lpApplicationName, //可执行文件名称(绝对或相对路径均可),也可以为NULL
  LPTSTR lpCommandLine, //上面的参数为NULL时用空格前指定exe名称,空格后或者上边参数不为NULL时为普通commandline
  LPSECURITY_ATTRIBUTES lpProcessAttributes, //进程安全描述符
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  //线程安全描述符
  BOOL bInheritHandles, //指定是否继承父进程的可继承句柄
  DWORD dwCreationFlags,//指定附加的、用来控制优先类和进程的创建的标志,如CREATE_SUSPENDED创建之后不运行(可以做些设置动作),直到调用ResumeThread才会运行
  LPVOID lpEnvironment, //指向一个新进程的环境块。如果此参数为空,新进程使用调用进程的环境。
  LPCTSTR lpCurrentDirectory, //指向一个以NULL结尾的字符串,这个字符串用来指定子进程的工作路径。
  LPSTARTUPINFO lpStartupInfo, //指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。
  LPPROCESS_INFORMATION lpProcessInformation //指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。作为返回值
);
相对应的关闭销毁进程的函数有ExitProcess、TerminateProcess用于终止线程。系统要保证所有的内核对象不会泄漏在进程终止时要处理如下事项:


清理的动作更像是异常处理中的finally语句块,而终止线程更像是抛出异常。故而终止线程的时机变得重要(类比于抛出异常),通常有如下终止线程的方式(括号中以异常处理作为类比):

1:主线程从入口函数返回。(相当于正常结束,执行finally清理)
2:进程中的一个线程调用ExitProcess。(在执行过程中抛出异常)
3:另一个进程中的线程调用TerminateProcess。(直接改变指令内容为调用ExitProcess)
4:所有线程结束。(没有线程程序做不了任何事情,系统调用TerminateProcess)

进程启动后在运行的过程中有些资源能够访问而有些资源不能访问,这种运行权限在启动之初就已经确定无法在中途改变若要改变需要重新设定权限之后重启进程。一般在程序的资源文件中以RT_MANIFEST定义,或者与可执行文件名称相同的.manifest文件中定义。

进程创建之后由系统进行管理,我们似乎对进程失去了控制,还好windows提供了Job内核对象,让进程与作业相关联我们就可以通过作业来对作业中的进程做统一的管理了。最好把作业对象想象成一个进程容器。与其他内核对想一样我们可以通过Create或者Open来创建或打开作业对象,再通过AssginProcessToJobObject将进程加入到作业中,进程加入作业后就不能改变了。当所有相关的进程都创建出来并加入到作业后,就可以通过SetInfomationJobObject接口来对作业中的所有的内核对象做出限制,并使用接口QueryInfomationJobObject可以查询这些限制。最后可以通过TerminateJobObject来结束作业中的所有进程。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值