三、 Windows里面的进程(Process)和线程(Thread)

首先,我们应该知道,windows调度的单位是线程而不是进程!


从而,我们认识一下核心对象(系统资源)
这里写图片描述


进程的生死周期:
这里写图片描述
当然,你也可以编写一个程序,使用CreateProcess函数创建一个新的进程去调用其他的程序。

BOOL CreateProcess(
  LPCTSTR lpApplicationName, // pointer to name of executable module
  LPTSTR lpCommandLine,  // pointer to command line string
  LPSECURITY_ATTRIBUTES lpProcessAttributes,  // process security attributes
  LPSECURITY_ATTRIBUTES lpThreadAttributes,   // thread security attributes
  BOOL bInheritHandles,  // handle inheritance flag
  DWORD dwCreationFlags, // creation flags
  LPVOID lpEnvironment,  // pointer to new environment block
  LPCTSTR lpCurrentDirectory,   // pointer to current directory name
  LPSTARTUPINFO lpStartupInfo,  // pointer to STARTUPINFO
  LPPROCESS_INFORMATION lpProcessInformation  // pointer to PROCESS_INFORMATION
);

以下是《深入浅出MFC中的参数解析》,详细的可查MSDN
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
按理来说,shell创建了一个新进程,那么他就是shell的子进程了,然而实际上,shell在创建了一个新进程之后,它就切断了该进程与自己的父子关系,如下使用CloseHandle就可以实现上面的操作:
这里写图片描述


线程的生死周期:
这里写图片描述
我们使用CreateThread函数创建一个线程在调用进程的地址空间。

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // 线程的安全属性
  DWORD dwStackSize,                         // 初始化线程的栈大小
  LPTHREAD_START_ROUTINE lpStartAddress,     // 线程需要处理的函数(content)
  LPVOID lpParameter,                        // 线程处理函数的参数
  DWORD dwCreationFlags,                     // 线程创建的附加标识
  LPDWORD lpThreadId                         // 返回线程的id
);

下面是MSDN里面的参数解析
Parameters
lpThreadAttributes
指向一个SECURITY_ATTRIBUTES 结构的 that确定返回的句柄是否可以由子进程继承。如果被子进程是null,手柄不能被继承。
Windows NT: 该结构的lpSecurityDescriptor成员指定为新的线程安全描述符。如果被子进程是空的,线程获取默认安全描述符.
dwStackSize
指定堆栈的初始提交大小,以字节为单位。系统将该值旋转到最近的页面。如果该值为零,或者小于默认提交大小,则默认使用与调用线程相同的大小。有关更多信息,请参见线程堆栈大小.
lpStartAddress
应用程序定义的函数指针类型LPTHREAD_START_ROUTINE被线程执行的线程的起始地址。在线程函数的更多信息。
lpParameter
指定传递给线程的单个32位参数值。
dwCreationFlags
指定控制线程创建的附加标志。如果create_suspended标志指定, 线程处于挂起状态了,也不会跑到resumethread函数被调用。如果此值为零,则线程在创建后立即运行。此时,没有其他值被支持。
lpThreadId
指向接收线程标识符的32位变量的指针。.
Windows NT:如果此参数为空,则不返回线程标识符。
Windows 95和Windows 98:此参数可能不是null。
返回值:
如果函数创建成功,则返回该线程句柄,如果失败,返回NULL。错误信息调取函数GetLastError。

与此同时,我们不能忘了C runtime函数库里面也有一个创建线程的方法:_beginthreadex

uintptr_t _beginthread( // NATIVE CODE  
   void( __cdecl *start_address )( void * ),  
   unsigned stack_size,  
   void *arglist   
);  
uintptr_t _beginthread( // MANAGED CODE  
   void( __clrcall *start_address )( void * ),  
   unsigned stack_size,  
   void *arglist   
);  
uintptr_t _beginthreadex( // NATIVE CODE  
   void *security,  
   unsigned stack_size,  
   unsigned ( __stdcall *start_address )( void * ),  
   void *arglist,  
   unsigned initflag,  
   unsigned *thrdaddr   
);  
uintptr_t _beginthreadex( // MANAGED CODE  
   void *security,  
   unsigned stack_size,  
   unsigned ( __clrcall *start_address )( void * ),  
   void *arglist,  
   unsigned initflag,  
   unsigned *thrdaddr   
);  

参数
start_address
启动开始执行新线程的例程的地址。 对于 _beginthread,调用约定是 __cdecl (针对本机代码)或 __clrcall (针对托管代码);对于_beginthreadex,它是 __stdcall (针对本机代码)或 __clrcall (针对托管代码)。
stack_size
新线程的堆栈大小或 0。
arglist
要传递到新线程的参数列表或 NULL。
Security
指向 SECURITY_ATTRIBUTES 结构的指针,此结构确定返回的句柄是否由子进程继承。 如果 Security 为 NULL,则不能继承句柄。 对于 Windows 95 应用程序,必须为 NULL。
initflag
控制新线程的初始状态的标志。 将 initflag 设置为 0 以立即运行,或设置为 CREATE_SUSPENDED 以在挂起状态下创建线程;使用 ResumeThread来执行此线程。 将 initflag 设置为 STACK_SIZE_PARAM_IS_A_RESERVATION 标志以将 stack_size 用作堆栈的初始保留大小(以字节计);如果未指定此标志, stack_size 将指定提交大小。
thrdaddr
指向接收线程标识符的 32 位变量。 如果此变量为 NULL,则不可用。
返回值
如果成功,则这些函数中的每一个都会返回一个句柄到新创建的线程;但是,如果新创建的线程退出过快,则 _beginthread 可能不会返回有效句柄。 (请参见“备注”节中的讨论。)发生错误时,_beginthread 返回 -1L,并在线程过多的情况下将 errno 设置为 EAGAIN;如果参数无效或堆栈大小错误,则设置为 EINVAL;如果资源(如内存)不足,则设置为 EACCES。 发生错误时, _beginthreadex 返回 0 并设置 errno 和 _doserrno 。
如果 startaddress 为 NULL,则会调用无效的参数处理程序,如 Parameter Validation所述。 如果允许执行继续,则这些功能将 errno 设置为EINVAL 并返回 -1。


线程优先级:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
总结来看,其优先级可以看做:
这里写图片描述

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huichangxindong/article/details/79960693
个人分类: 深入浅出MFC
上一篇二、 Consolo 程序
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭