1、基础概念
进程:操作系统为用户的每个需求活动所开辟的任务,允许用户同时在操作系统上执行多个任务。如果进程内执行某个操作让该进程暂停,那么就会切换进程,执行别的进程或等待。
进程改进:在一个任务内会有很多的内部小任务,如果这些小任务互相之间也需要共同进行,当一个进程内的某个小任务暂停,就会在进程内切换小任务或者(对于分时系统)时间耗尽,切换进程
线程:加入线程的机制后,会让用户的操作任务更加灵活,而且可以更大限度的减少进程间的切换,(进程间的切换会耗费很多资源,而且浪费CPU时间)
进程的切换:现在进程正在执行,当要进行切换时,把该进程的数据资源、寄存器、堆栈、内存空间的使用、进程当前执行的代码位置等,给这些所有东西拍个照片做个记录,然后把要切换的那个任务的所有照片拿出来,一 一进行恢复,然后CPU就切换到该进程执行,进程就被切换掉
线程的切换:线程是属于进程内部的资源,同时也属于内核资源,线程被称为“轻量级线程”,就是因为切换时不会像进程那样附带很多资源信息,导致拍照繁琐,照片量大,整个过程消耗时间长,所以线程的切换比进程要快的多,也很轻巧,所以线程是操作系统中可执行的最小任务
Windows是多任务分时操作系统,支持进程和多线程。
进程组成:
1、进程内核对象
2、地址空间
线程组成:
1、线程的内核对象,操作系统用它管理线程
2、线程栈,用于维护线程执行时所需的所有参数和局部变量
每个进程至少有一个线程。
进程是有惰性的,进程从来不执行任何东西,只是一个线程的容器 ,线程在其进程的地址空间内执行代码和处理数据,这些线程将共享内核对象句柄。
2、何时创建线程
线程描述了进程内部的一条执行线路,每次初始化进程时,系统都会创建一个主线程。
对于用Microsoft C/C++编译器生成的应用程序,这个线程首先会执行C/C++ 运行库的启动代码,后者调用入口点函数(_tmain 或 _tWinMain),并继续执行,直至入口点函数返回C/C++ 运行库的启动代码,后者最终调用ExitProcess。
主线程是应用程序必须的,同时可以创建其它线程进行辅助工作
3、编写第一个线程函数
每个线程都必须有一个入口点函数,这是线程执行的起点,主线程入口点:(_tmain 或 _tWinMain),所以创建的线程也必须要有一个入口函数:
DWORD WINAPI ThreadFunc(LPVOID param){
DWORD dwResult = 0;
......
return (dwResult );
}
最后线程函数将终止并返回,此时线程将终止运行,用于线程栈的内存也会被释放,
线程内核对象的使用计数也会递减,计数为0时,线程内核对象会被销毁。
线程函数的注意点:
- 线程入口函数由我们自己指定,应避免重复
- 线程函数只有一个参数
- 线程函数必须返回一个值,作为该线程的退出代码
- 线程函数应尽量使用函数参数和局部变量,因为函数的参数和局部变量是在线程栈上创建的。使用静态/全局变量时,多个线程可以同时访问,这样可能会破坏数据。
4、CreateThread 函数
知道如何实现线程函数后,接下来要让操作系统创建一个线程来执行线程函数
调用CreateThread 函数,系统会创建一个线程内核对象,这个内核对象是一个数据结构,操作系统用这个结构来管理线程。
系统从进程的地址空间中分配内存给线程栈使用,新线程在与负责创建的那个线程在相同的进程上下文中运行。因此,新线程可以访问内核对象的所有句柄、进程中的所有内存、同一进程的其它线程栈,这样同进程的线程间可以很容易通信
//参数中有很多默认,是因为在CreateProcess时,就已经CreateThread初始化过进程的主线程
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
//1、用来描述线程的安全属性的指针,NULL表示使用默认的安全描述符
DWORD dwStackSize,
//2、分配该线程的堆栈大小,NULL表示与创建自己的线程相同
LPTHREAD_START_ROUTINE lpStartAddress,
//3、线程的入口函数地址
LPVOID lpParameter,
//4、传递给线程的参数
DWORD dwCreationFlags,
//5、NULL表示立即调度,CREATE_SUSPEND表示挂起
LPDWORD lpThreadId
//6、线程相关的标识符返回(新线程的ID,一般为NULL)
);
5、终止运行线程
线程可以通过以下4中方法终止运行:
- (自然死亡法)线程函数返回
让线程函数返回,可以确保清理以下:
1、线程函数中创建的所有C++对象的应用程序清理工作都得以执行
2、操作系统正确释放线程栈使用的内存
3、操作系统把线程的退出代码设为线程函数的返回值
4、系统递减线程的内核对象的使用计数
- (无奈死亡法)线程通过调用ExitThread函数杀死自己
VOID ExitThread(DWORD dwExitCode);
该函数将终止线程的运行,并导致操作系统清理该线程使用的所有操作系统资源,但是你的C/C++资源(如C++类对象)不会被销毁。
- (突然死亡法)同一进程或另一进程中的线程调用 TerminateThread函数
BOOL TerminateThread(
HANDLE hThread, //标识了要终止的那个线程的句柄
DWORD dwExitCode ); //线程终止运行时,其退出代码将变成你作为dwExitCode 参数传递的值,线程的内核对象使用计数递减
不同于ExitThread总是杀死主调线程,TerminateThread能杀死任何线程。
该函数是异步的,就是在线程函数返回前,线程已经终止,所以应加上WaitForSingleObject函数
- (意外死亡法)包含线程的进程终止运行
当进程终止时(ExitProcss、TerminateProcess),会终止该进程内所有的线程,强制杀死所有线程,释放进程所有的资源进行清理
一旦线程不在运行,系统中就没有别的线程再用该线程的句柄,其他线程可以调用GetExitCodeThread函数来检查线程是否已经终止运行,其退出代码是什么。如果线程未终止,退出代码为STILL_ACTIVE标识符(0x103),函数调用成功返回TRUE。
BOOL GetExitCodeThread(
HANDLE hTread, //要进行检查的线程的线程句柄
PDWORD pdwExitCode); //保存其退出代码
6、线程内幕
CreateThread调用后,创建一个线程内核对象:
1、对象使用计数为:2(为0销毁线程)
2、线程挂起计数为:1(为0是可调度)
3、退出代码为:STILL_ACTIVE(0x103)
4、对象被设置为未触发状态
5、从进程的地址空间分配线程的堆栈,系统会把(线程函数的参数、线程函数入口地址)首先压入堆栈,(堆栈增长方向:高地址->低地址)
6、每个线程都有自己的一组CPU寄存器,称为线程的上下文(CONTEXT结构WinNT.h)
原文地址:https://blog.csdn.net/qq_42856154/article/details/90749952
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。