C++中的线程和进程

更新时间:2023-05-15 12:11:52 阅读: 评论:0

说到线程就不得不先说进程,进程通常被定义为一个正在运行的程序的实例。进程是一个正在运行的程序,它拥有自己的虚拟地址空间,拥有自己的代码、数据和其他系统资源,如进程创建的文件、管道、同步对象等,一个进程也包含了一个或者多个运行在此进程内的线程。
那进程和程序又有什么区别了?虽然程序和进程在表面上很相似,但是它们有者根本的区别。程序是一连串静态的指令,而进程是一个容器,它包含了一系列运行在这个程序实例上下文中的线程使用的资源。
一个进程通常定义为程序的一个实例。在Win32中, 进程占据4GB的地址空间。与它们在MS-DOS和16位Windows操作系统中不同, Win32进程是没有活力的。这就是说,一个Win32进程并不执行什么指令,它只是占据着4GB的地址空间,此空间中有应用程序EXE文件的 代码和数据。EXE需要的任意DLL也将它们的代码和数据装入到进程的地址空间。除了地址空间,进程还占有某些资源,比如文件、动态内存分配和线程。当进程终止时,在它生命期中创建的各种资源将被清除。
但是进程是没有活力的,它只是一个静态的概念。为了让进程完成一些工作,进程必须至少占有一个线程,所以线程是描述进程内的执行,正是线程负责执行包含在进程的地址空间中的代码。实际上,单个进程可以包含几个线程, 它们可以同时执行进程的地址空间中的代码。为了做到这一点,每个线程有自己的一组CPU寄存器和堆栈。
每个进程至少有一个线程在执行其地址空间中的代码,如果没有线程执行进程 地址空间中的代码, 进程也就没有继续存在的理由,系统将自动清除进程及其地址空间。为了运行所有这些线程,操作系统为每个独立线程安排一些CPU 时间,操作系统以轮转方式向线程提供时间片,这就给人一种假象,好象这些线程都在同时运行。创建一个Win32进程时,它的第一个线程称为主线程,它 由系统自动生成,然后可由这个主线程生成额外的线程,这些线程,又可生成更多的线程。
1.线程的创建
线程的创建是通过函数CreateThread来实现的,调用成功返回句柄和一个id。
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,  //线程的安全属性
DWORD dwStackSize,                                            //线程堆栈的大小
LPTHREAD_START_ROUTINE lpStartAddress,    //线程函数的起始地址
LPVOID lpParameter,                                                //传递个线程函数的参数
DWORD dwCreationFlags,                                        //线程创建后是否立即启动
LPDWORD lpThreadId                                            //线程的ID号
);
每个线程
都要都要有个入口函数(也就是线程函数),
下面是一个线程函数定义的例子:DWORD WINAPI ThreadProc(LPVOID lpParam);
吃什么水果能长高WINAPI是个宏 #define WINAPI _stdcall;
其中lpThreadAttributes参数为一个指向SECURITY_ATTRIBUTES结构的指针。如果想让对象为缺省安全属性的话,可以传一个NULL,如果想让任一个子进程都可继承一个该线程对象句柄,必须指定一个SECURITY_ATTRIBUTES结构,其中bInheritHandle成员初始化为TRUE。
参数dwStackSize表示线程为自己所用堆栈分配的地址空间大小,0表示采用系统缺省值。
参数lpStartAddress用来表示新线程开始执行时代码所在函数的地址,即为线程函数。
lpParameter为传入线程函数的参数,
dwCreationFlags参数指定控制线程创建的附加标志,可以取两种值。如果该参数为0,线程就会立即开始执行,如果该参数为CREATE_SUSPENDED,则系统产生线程后,初始化CPU,登记CONTEXT结构的成员,准备好执行该线程函数中的第一条指令,但并不马上执行,而是挂起该线程。
最后一个参数lpThreadId 是一个DWORD类型地址,返回赋给该新线程的ID值。
2.线程的内核对象
线程内核对象就是一个数据结构,包含了线程的一些信息。当成功调用CreateThread后,系统都会在内部为新线程分配一个内核对象。
内核对象的基本成员:
Context
Context也就是线程上下文,包括了一组CPU寄存器,反映了线程上次运行时CPU寄存器的状态。
Usage Count
入职申请书>共阳极数码管
Usage Count就是线程的使用计数。线程只要没有结束,Usage Count就至少为1。当这个值为0时,系统就认为已经没有任何进程在引用此内核对象了,于是线程内核对象就要从内存中撤销。在创建一个新的线程时,CreateThread函数返回内核对象的句柄,相当于打开一次新创建的内核对象,这会促使Usage Count加1,所以创建一个新的线程后,Usage Count就是2。调用函数OpenThread会使Usage Count再次加1,而CloHandle会使Usage Count减1。
Suspend Count
Suspend Count暂停次数。用ResumeThread函数可以唤醒一个线程,会减少Suspend Count,当Suspend Count为0时线程被恢复运行。用SuspendThread函数挂起一个线程,这个函数会增加Suspend Count。
Exit Code
Exit Code就是线程退出代码(也就是线程函数的返回值),当线程函数还没有执行完时,Exit Code的值就是STILL_ACTIVE。
Signaled
Signaled指示线程对象是否为”受信”状态。线程运行时Signaled永远是Fal也就是未受信。只有线程
结束后才是受信状态。
3.线程的优先级
首先得说下Windows调度线程的原则:只有优先级最高的线程是可调度的,操作系统就不会将CPU分配给优先级低的。但是有些方法会使线程暂停或者不可调度,如WaitForSingleOb
ject或者GetMessage,这样优先级低的就可以分配到CPU的时间片,一旦优先级高的线程被唤醒了,优先级低的线程将被阻塞。Windows支持6个优先级类:idle、below normal、normal、above normal、high、real-time。
设定线程的相对优先级
我不会喜欢你歌词当一个线程被首次创建时,它的优先级等同于它所属进程的优先级。在单个进程内可以通过调用SetThreadPriority函数改变线程的相对优先级。一个线程的优先级是相对于其所属的进程的优先级而言的。
乡村女医生BOOLSetThreadPriority(HANDLE hThread,intnPriority);
其中参数hThread是指向待修改 优先级线程的句柄,nPriority可以是以下的值:
THREAD_PRIORITY_LOWEST,
THREAD_PRIORITY_BELOW_NORMAL,
THREAD_PRIORITY_NORMAL,
微型党课讲稿THREAD_PRIORITY_ABOVE_NORMAL,
THREAD_PRIORITY_HIGHEST
4.线程的终止
终止线程有4种方法:
1.      使用ExitThread函数终止线程
采用这种方法终止线程,会使系统释放掉此线程使用的所有资源但是c/c++资源却不能得到正确的清除。
2.      使用TerminateThread函数在一个线程中强制终止另一个线程的执行
使用TerminateThread函数终止线程,系统不会释放线程使用的堆栈,所以除非迫不得已,尽量避免使用这个函数终止线程。
3.      使用ExitProcess函数结束进程
使用这个方法相当与对进程中的每个线程使用TerminateThread函数。
4.      线程函数自然退出
这种方法是最好的,线程函数返回时Windows将终止线程的执行。
函数说明:
Handle OpenThread(
DWORD dwDesiredAccess,    //想要访问的权限
战略的重要性BOOL bInheritHandle,            //此函数返回的句柄是否可以被子进程继承
DWORD deThreadId              //目标线程的ID
)
Void ExitThread(DWORD dwExitCode);//dwExitCode线程的退出代码
BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);//hThread目标线程句柄
5、挂起及恢复线程
孔孟朱王先前我提到过可以创建挂起状态的线程(通过传递CREATE_SUSPENDED标志给函数CreateThread来实现)。当你这样做时,系统创建指定线程的核心对象,创建线程的栈,在CONTEXT结构中初始化线程CPU注册成员。然而,线程对象被分配了一个初始挂起计数值1,这表明了系统将不再分配CPU去执行线程。要开始执行一个线程,另一个线程必须调用ResumeThread并传递给它调用CreateThread时返回的线程句柄。
DWORD ResumeThread(HANDLEhThread);
一个线程可以被挂起多次。如果一个线程被挂起3次, 则该线程在它被分配CPU之前必须被恢复3次。除了在创建线程时使用CREATE_SUSPENDED标志,你还可以用SuspendThread函数挂起线程。
DWORDSuspendThread(HANDLE hThread);

本文发布于:2023-05-15 12:11:52,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/899425.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:线程   进程   函数   对象   执行   地址   创建   空间
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图