线程基础

来源:互联网 发布:https的端口号是多少 编辑:程序博客网 时间:2024/05/18 12:44
每个进程至少有一个线程,线程由两部分组成
1、线程的内核对象,操作系统用线程内核对象管理线程,操作系统还用内核对象存放线程统计信息的地方
2、线程栈,用于维护线程执行时所需要的所有函数参数和局部变量

线程与进程的关系
进程是惰性的,进程从来不执行任何东西,它只是一个线程的容器,线程必然是在某个进程的上下文中创建,线程在其进程的地址空间内执行代码和处理数据直至消亡,同一个进程内线程共享地址空间、代码、数据,共享内核对象句柄,因为句柄表针对的是进程,而不是线程。
相对与线程,进程有所使用的系统资源更多,原因在于地址空间,进程创建一个虚拟的地址空间需要大量的系统资源,系统中会有大量的记录活动,而这需要大量的内存。而且,.exe、.dll文件要记载到一个地址空间,需要使用文件资源,另外一方面,线程使用的系统资源要少得多。事实上,线程只有一个内核对象和一个栈,几乎不涉及记录活动,所及不需要占用多少内存。

线程创建与终止
每个线程函数都有一个入口点函数,这是线程 的执行起点,DWORD WINAPI ThreadFunc(PVOID lpParam)线程函数可以执行我们指定的任务,最终,线程函数将终于运行并返回。此时,线程将终止运行,用于线程栈 的内存也会被释放,线程内核对象的使用计数也会递减,如果使用技术变成0,线程内核对象会被销毁,线程内核对象的寿命至少可以达到它们关联的线程那样长,不过,对象的寿命可能超过线程本身的寿命。

线程函数需要注意以下几点:
1、如果应用程序中有多个线程函数,必须为它们指定不同名称,否则编译器会认为创建了一个函数的多个实现
2、线程函数只有一个参数,而且其意义有程序控制(非操作系统)
3、线程函数必须有一个返回值,它将成为该线程的退出代码
4、线程函数应该尽量使用函数参数和局部变量,使用静态变量和全局变量时,多个线程可以同时访问这些变量会破坏内容。然而,由于函数的参数和局部变量是在线程栈上创建,不太可能被其他线程破坏。

使用CreateThread函数创建线程,调用CreateThread函数时,系统会自动创建一个内核对象,这个线程内核对象不是线程本身,而是一个较小的数据结构,操作系统通过这个结构来管理线程。系统从进程的地址空间分配内存给线程栈使用,新线程在与负责创建的那个线程在相同的进程上下文运行。因此,新线程可以访问进程内核对象的所有句柄、内存、线程栈。进程中的多个线程可以很容易相互通信。
注意:CreateThread函数是用于创建线程的Window函数,如果写的是C/C++代码,那绝对不要使用CreateThread函数,用_beginthreadex函数相比CreateThread函数有一定优势,对于CreateThread函数的参数以及_beginthreadex函数将在以后的博文中书写。

线程终止
 线程终止可以通过以下4种方法
1、线程函数返回,这是强烈推荐的。让线程函数返回,可以确保应用程序清理工作得以执行。
2、通过ExitThread函数杀死自己,该函数将终止线程运行,并导致操作系统清理该线程使用的所有操作系统资源,但是C/C++资源不会被销毁。
3、调用TerminateThread函数,可以杀死任何线程,为异步函数,无法直接判断线程是否终止,需要调用WaitForSingleObject函数查询线程是否终止,线程无法正确清理,而且不能组织自己被终止运行。
4、包含线程的进程终止运行。

线程终止运行时,线程拥有的所有用户对象句柄会被释放;线程的退出代码从STILL_ACTIVE变成ExitThread活TerminateThread的代码;线程的内核对象的状态编程触发状态,如果线程是进程的最后一个线程,进程也会被终止;线程内核对象的使用技术递减1
线程终止运行时,其关联的线程对象不会自动释放,除非这个对象的所有未结束的引用都被关闭了,一旦线程不再运行,系统就没有别的线程再用该线程的句柄了。但是,其他线程可以调用GetExitCodeThread来检查hThread所标识的那个线程是否终止,如果已终止,可以判断其退出代码是什么。












0 0