windows 进程学习

进程分2部分组成:

a.内核对象,操作系统管理内核对象,内核对象保存进程统计信息。

b.地址空间,包括可执行程序或dll的代码和数据。包括线程堆栈。

剖解:

a.进程间共享内核对象,所以可以通过内核对象命名的方法来实现进程通讯

b.不同的进程,内存地址不能共享,那就涉及进程间通讯了;同一进程的不同线程,内存地址共享。

window的入口点函数

但在实际运行中,在入口点函数前,会先执行c/c++ 运行时启动函数,进行初始化c/c++ 运行库,还有全局变量和静态c++对象构造。具体如下:

此外相关的函数有:

  1. getversionex:
  2. getcommandline:
  3. getenvironmentstrings
  4. getmodulefilename:获取运行程序的名称及其路径

有getmodulefilename 和 getmodulehandle():

getmodulehandle:找出可执行文件或dll被加载到进程地址空间的地址位置,如果传递NULL值,会返回进程的地址空间中可执行文件的基地址。所有即使调用getmodulehandle(NULL)的代码是一个DLL文件,返回值是可执行文件的基地址,非DLL文件的基地址。在dll中,还可以使用LoadLibrary。

getmoduleFileName():正在运行的程序及其完整路径。

GetProcAddress:功能是检索指定的动态链接库(DLL)中的输出库函数地址。

getcommandline:获取进程完整的命令行。

环境变量跟注册表的关系,使用regedit进行查看。

同时,从进程的主线程入口函数返回时,返回到c++运行库启动代码,执行c++资源释放(如c++对象的析构函数),然后c++运行库启动代码再显性调用exitprocess来终止线程。

进程的创建

createprocess函数解析:

1.pszapplicationname= null ,pszcommandline必须是可执行文件,可以在绝对路径或者是相对路径。

2.pszapplicationname不为null,必须有扩展名,当前目录或者指定目录 ,pszcommandline新的命令行参数,不能为直接填写常量字符串。

3.psaprocess 表示子进程内核对象安全属性。

4.psathread表示子进程的主线程的内核对象安全属性。

5.binherithandles=ture,表示子进程继承父进程可进程的评审组。

6.fdwcreate按位或标志组合,可以直接设置为0.

7.pvEnvironment = null,表示子进程继承父进程的环境变量。

8.pszcurdir=null,表示子进程的工作目录与父进程一样。

9.psistartinfo 所有成员初始化为0,并且是cb成员为结构的大小。

10.ppiprocinfo   指向process_information结构

会创建一个进程内核对象和线程内核对象,创建时系统会为每一个对象指定一个初始的使用计数1,CreateProcess返回时由于PROCESS_INFORMATION结构中再次引用了进程和线程内核对象 此时它们的使用计数都变为2。可以理解为进程和线程实例本身也占有一个计数。当它们结束运行时这个使用计数被递减1。

所以如果系统要释放进程对象,1:进程必须终止,此时使用计数递减1。2:父进程必须调用CloseHandle,使用计数再次减去1。线程类似。

进程id:getcurrentprocessid 或getprocessid   getprocessidofthread

线程id:getcurrentthreadid 或gettrheadid    

进程的退出

疑问:进程内核对象状态变成已触发状态怎理解?

进程初始化时为未触发状态,进程终止时自动变已触发状态。

为了断绝与子进程的联系,需在生成子进程的后,立即调用closehandle关闭新进程及其主线程的句柄。目的是使父进程的内核对象使用次数减1。

进程的终止方式

 解释:

 VOID WINAPI ExitProcess(_In_ UINT uExitCode);

只能退出自己当前的进程。

问题:直接终止运行,再也不会返回当前函数调用,会导致局部或全局的c++对象无法析构,无法释放内存。同理ExitThread也是一样。所以

TerminateProcess()

可以退出自己和别人的进程。也会导致和ExitProcess一样的结果:内存泄露

TerminateProcess()是异步执行的,在调用返回后并不能确定被终止进程是否已经真的退出,如果调用TerminateProcess()的进程对此细节关心,可以通过WaitForSingleObject()来等待进程的真正结束。

如果我们在编写应用程序时,打算终止当前进程,我们该调用哪个函数?答案是:三者其实都一样! 因为三者都可能导致内存泄露,但我们担心 的过多了,因为进程在结束时,即使有ExitProcess,TerminateProcess,以及exit函数调用而导致的内存泄露,OS也会进行清理工作,能保证 我们泄露的内存最终被还回到OS中去,而不必担心当前进程已经退出而导致内存泄露,致使其它进程无法使用该内存块。

因为:

一个进程无论在什么情 况下终止,都会进行如下工作:

1) 进程指定的所有用户对象和G U I对象均被释放,所有内核对象均被关闭(如果没有其他 进程打开它们的句柄,那么这些内核对象将被撤消。 但是,如果其他进程打开了它们的句柄, 内核对象将不会撤消)。

2) 进程的退出代码将从S T I L L _ A C T I V E改为传递给E x i t P r o c e s s或Te r m i n a t e P r o c e s s的代码。

3) 进程内核对象的状态变成收到通知的状态(关于传送通知的详细说明,参见第9章)。系 统中的其他线程可以挂起,直到进程终止运行。

4) 进程内核对象的使用计数递减1。

进程和线程的区别:
 

1.根本区别:进程是操作系统进行资源分配的最小单元,线程是操作系统进行运算调度的最小单元

2.从属关系不同:进程中包含了线程,线程属于进程。

3.开销不同:进程的创建、销毁和切换的开销都远大于线程。

4.拥有资源不同:每个进程有自己的内存和资源,一个进程中的线程会共享这些内存和资源

5.控制和影响能力不同:子进程无法影响父进程,而子线程可以影响父线程,如果主线程发生异常会影响其所在进程和子线程。一个进程崩溃,不会对其他进程产生影响,而一个线程崩溃,会让同一进程内的所有其他线程也死掉

6.CPU利用率不同:进程的CPU利用率较低,因为上下文切换开销较大,而线程的CPU的利用率较高,上下文的切换速度快。

7.操纵者不同:进程的操纵者一般是操作系统,线程的操纵者一般是编程人员。
 

进程间通讯办法:

进程间共享内核对象有以下三种方式:

  • 继承内核对象句柄
  • 命名内核对象
  • 复制DupilateHandle 

命名内核对象延伸文件映射内核对象(实现跨进程共享内存)

这里写图片描述

 1.创建文件内核对象,调用createfile.目的是为了告诉系统文件映射的物理存储器的位置。

2.创建文件映射内核对象 ,调用createfilemapping.目的就是系统需要多少的物理存储器。

   欲在其中创建映射的一个文件句柄。0xFFFFFFFF(-1,即INVALID_HANDLE_VALUE)表示在页面文件中创建一个可共享的文件映射,表明创建的文件映射对象的物理存储器不是磁盘的文件,而是系统从页交换文件中调拨物理存储器。即在磁盘c的pagefile.sys文件,因此不需要再调用createfile函数。

3.将文件的数据映射到进程的地址空间,调用mapviewoffile

4.从进程的地址空间撤销文件数据的映射,调用unmapviewoffile,释放进程地址空间。

5.关闭文件映射对象,调用closehandle

6.关闭文件对象,调用closehandle

进程间同步

1.事件量  参考:

2.互斥量 

3.信号量 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值