线程的基本知识

上传人:ss****gk 文档编号:235612927 上传时间:2022-01-06 格式:DOC 页数:14 大小:76KB
返回 下载 相关 举报
线程的基本知识_第1页
第1页 / 共14页
线程的基本知识_第2页
第2页 / 共14页
线程的基本知识_第3页
第3页 / 共14页
线程的基本知识_第4页
第4页 / 共14页
线程的基本知识_第5页
第5页 / 共14页
点击查看更多>>
资源描述

《线程的基本知识》由会员分享,可在线阅读,更多相关《线程的基本知识(14页珍藏版)》请在金锄头文库上搜索。

1、第6章线程的基础知识 理解线程是非常关键的,因为每个进程至少需要-个线程。本章将更加详细地介绍 线程的知识。尤其是要讲述进程与线程之间存在多人的差别,它们各自具冇什么作 用。还要介绍系统如何使用线程内核对彖來管理线程。与进程内核对象一样,线程 内核对象也拥有屈性,我们将耍观察许多用丁查询和修改这些屈性的两数。此外还 要介绍可以在进程中创建和生成更多的线程时所用的函数。第4章介绍了进程是由两个部分构成的,一个是进程内核对象,另一-个是地址空间。 同样,线程也是由两个部分组成的:一个是线程的内核对象,操作系统用它来对线程实施管理。内核对象也是系统用 来存放线程统计信息的地方。另个是线程堆栈,它用于

2、维护线程在执行代码时需要的所冇函数参数和局部变 量(第1 6章将进一步介绍系统如何管理线程堆栈)。第4章中讲过,进程是不活泼的。进程从来不执行任何东西,它只是线程的容器。 线程总是在某个进程环境中创建的,而且它的整个寿命期都在该进程中。这意味着 线程在它的进程地址空间中执行代码,并在进程的地址空间中对数据进行操作。 因此,如果在单进程环境中,你有两个或多个线程止在运行,那么这两个线程将共 享单个地址空间。这些线程能够执行相同的代码,对相同的数据进行操作。这些线 程还能共享内核对象句柄,I大I为句柄表依赖于每个进程而不是每个线程存在。如你所见,进程使用的系统资源比线程多得多,原因是它需要更多的地

3、址空间。为 进程创建一个虚拟地址空间需要许多系统资源。系统中要保留大量的记录,这要占 用大量的内存。另外,出丁exe和dll文件耍加载到一个地址空间,因此也需耍 文件资源。而线程使用的系统资源要少得多。实际上,线程只有一个内核対象和一 个堆栈,保留的记录很少,因此需要很少的内存。由:线程需要的开销比进程少,因此始终都应该设法用增加线程來解决编程问题, 而要避免创建新的进程。但是,这个建议并不是一成不变的。许多程序设计用多个 进程来实现会更好些。应该懂得权衡利弊,经验会指导你的编程实践。在详细介绍线程之前,首先花一点时间讲讲如何正确地在应用程序结构中使用线 程。6.1何时创建线程线程用丁描述进程

4、中的运行路径。每当进程被初始化时,系统就要创建一个主线程。 该线程与C/C + +运行期库的川动代码一道开始运行,川动代码则调用进入点函数(main、w m a i n Wi n M a i n或wWinMain),并且继续运彳亍直到进入点 函数返Ini并且0/C + +运行期库的启动代码调用ExitProcess为止。对丁许 多应用程序來说,这个主线程是应用程序需要的唯-线程。不过,进程能够创建更 多的线程来帮助执行它们的操作。每个计算机都拥有-个功能非常强人的资源,即CPUo让CPU闲置起来是绝对 没冇道理的(如果忽略节省电能问题的话)。为了使CPU处于繁忙状态Z中,可 以让它执行各种不同

5、的工作。下面是一些例子:可以打开Microsoft Windows 2000配备的内容索引服务程序。它能够创建一个低 优先级的线程,以便定期打歼你的磁盘驱动器上的文件内容并给内容做索引。若要 找到一个文件,可以打开Search Result (搜索结果)窗口(方法是单击Start按 钮,从Search菜单中选泄For Files Or Folders),再将你的搜索条件输入 Containing Te x t 这时就可以搜索到索引,相关的文件就会立即显示出来。内 容索引服务程序大大改进了性能,I大I为每次搜索不必打开、扫描和关闭磁盘驱动器 上的每个文件。可以使用Windows 2000配备的磁

6、盘碎片整理软件。通常情况下,这种类型的实 用程序拥有许多管理选项,一般用户可能不懂,比如该实用稈序应该相隔多长时间 运行一次,何时运行。使用低优先级线程,可以在后台运行该实用程序,并R在系 统空闲吋对驱动器进行碎片整理。可以很容易地设想将來版木的编译器,每当暂停键入时,它就可以自动编译你的 源代码文件。输出窗口可以向你(儿乎)实时显示警告和出错信息。当键入变量和 函数名时出现错误时,就能立即发现。在某种程度上讲,Microsoft Visual Studio 已经实现了这个功能,使用Workspace的Class Vi ew窗格,就能够看到这 些信息。电子表格应用程序能够在后台执行各种计算。字

7、处理程序能够执行垂新分页、拼写和语法检查及在后台进行打印。文件可以在后台拷贝到其他介质中。Web浏览器在后台与它们的服务器进行通信。因此,在来门当前Web站点的结 果输入之前,用户可以缩放浏览器的窗口或者转到另一个Web站点。这些例了中,有一个重要问题应该注意,那就是多线程能够简化皿用程序的用户界 面。如果每当停止键入时,编译器建立了你的应用程序,那么就没有必耍提供Build 菜单选项。文字处理应用程序不需要Check Spelling(拼写检查)和Check Grammar (语法检查)菜单选项。在Web浏览器的例子中,注意,将不同的线程用于I/O (网络、文件或其他),应 用程序的用户界面

8、就能够始终保持工作状态。比如有一个应用程序负责给数据库记 录进行排序、打印文档或拷贝文件。如果将独立的线程用于处理这个与I/O相关的 任务,用户就可以在进程中继续使用应用程序界面来取消操作。设计一个拥有多线程的应用程序,就会扩大该应用程序的功能。我们在下一章中可 以看到,每个线程被分配了一个CPUo因此,如果你的计算机拥有两个CPU, 你的应用程序中有两个线程,那么两个CPU都将处于繁忙状态。实际上,你是让 两个任务在执行一个任务的时间内完成操作。每个进程至少拥有一个线程。因此,如呆你在应用程序中不执行任何特殊的操作, 在多进程操作系统上运行,就能够得到许多好处。例如,可以建立一个应用程序,

9、并同吋使用文字处理程序(我常常这样做)。如果计算机拥有两个CPU,那么该应 用程序就可以在一个处理器上执行,而另一个处理器则负责处理文档。另外,如果 编译器出现一个错误,导致它的线程进入一个无限循环,仍然可以使用其他的进程(1 6位Wi n d o w s和M SD 0 S应用程序则不行)6.2何时不能创建线程至今为止,一直在讨论多线程应用程序的优点。虽然多线程应用程序的优点很多, 但是它也存在某些不足之处。有些开发人员认为,解决问题的方法是将它分割成多 个线程。这种想法是完全错误的。线程确实是非常有用的,但是,当使用线程时,在解决原有的问题时可能产化新的 问题。例如,你开发了一个文字处理应用

10、程序,并且想耍让打印函数作为它自己的 线程来运行。这听起来是个很好的主意,I大I为用户可以在打印文档时立即回头着乎 编辑文档。但是,这意味着文档中的数据町能在文档打印时变更。也许最好是不要 让打印操作在它自己的线程中发牛,不过这种“方案”看起来冇点儿极端。如果你讣 用户编辑另一个文档,但是锁定止在打印的文档,使得打印结束前该文档不能修改, 那将会怎样呢?这里还有第三种思路,将文档拷贝到一个临时文件,然后打印该临 时文件的内容,并让用户修改原始文档。当包含该文档的临时文件结束打印时,删 除临吋文件。如你所见,线程能够解决某些问题,但是却乂会产个新的问题。在开发应用程序的 用户界面时,很可能出现对

11、线程的另一种误用。几乎在所冇的应用程序中,所冇用 户界面的组件(窗口)应该共享同一个线程。单个线程应该创建窗口的所有子窗口。 有时在不同的线程上创建不同的窗口是有用的,不过这种情况确实非常少见。通常情况下,一个应用程序拥有一个用户界面线程,用于创建所有窗口,并且有一 个GetMessage循环。进程中的所有其他线程都是工作线程,它们与计算机 或丨/0相关联,但是这些线程从不创建窗口。另外,一个用户界面线程通常拥有比 工作线程更高的优先级,因此用户界面负责向用户作出响应。虽然单个进程拥有多个用户界面线程的情况并不多见,但是这种情况有着某种有效 的用途。Windows Explorer为每个文件夹

12、窗口创建了一个独立的线程。它使你能够 将文件从一个文件夹拷贝到另一个文件夹,并R仍然可以査看你的系统上的其他文 件夹。另外,如果Explorer中存在一个错误,那么负责处理文件夹的线程可能 崩溃,但是仍然能够对其他文件夹进行操作,至少在执行的操作导致其他文件夹也 崩溃之前,仍然可以对它们进行操作(关于线程和用户界面的详细说明,参见第2 6 和2 7章)。上述内容的实质是应该慎重地使用多线程。不要想用就用。仅仅使用赋予进程的卞 线程,就能够编写出许多非常有用的和功能强大的应用程序。6.3编写笫一个线程函数每个线程必须拥有一个进入点函数,线程从这个进入点开始运行。前面已经介绍了 主线程的进入点函数

13、:即m a i n w m a i n Wi n M a i n或w Win Main。如果 想要在你的进程中创建一个辅助线程,它必定也是个进入点函数,类似下面的样子:DWORD WINAPI ThreadFunc(PVOID pvParam)DWORD dwResult = 0; return(dwResult);你的线程函数可以执行你想要它做的任何任务。最终,线程函数到达它的结尾处并 且返回。这时,线程终止运行,该堆栈的内存被释放,同时,线程的内核对象的使 用计数被递减。如果使用计数降为0,线程的内核对象就被撤消。与进程内核对象 的情况相同,线程内核对象的寿命至少町以达到它们相关联的线程那

14、样长,不过, 该对象的寿命可以远远超过线程本身的寿命。下面对线程函数的儿个问题作一说明:主线程的进入点函数的名字必须是main、wmain、Wi n M a i n或 wWinMain, 这些函数不同的是,线程函数可以使用任何名字。实际上,如果 在应用程序中拥冇多个线程旳数,必须为它们赋予不同的名字,否则编译器/链接程 序会认为你为单个函数创建了多个实现函数。由于给你的主线程的进入点函数传递了字符串参数,因此可以使用 ANSI/Unicode 版本的进入点函数: main/wmain 和 WinMain/wWinMaino可以给线程函数传递单个参数,参数的含义由你而不 是由操作系统來定义。因此

15、,不必担心A N S I / U ni code问题。线程函数必须返回一个值,它将成为该线程的退出代码。这与C/C + +运行期库 关于让主线程的退出代码作为进程的退出代码的原则是相似的。线程函数(实际上是你的所有函数)应该尽可能使用函数参数和局部变量。当使 用静态变量和全局变量时,多个线程可以同时访问这些变量,这可能破坏变量的内 容。然而,参数和局部变量是在线程堆栈中创建的,因此它们不太可能被另一个线 程破坏。既然懂得了实现线程函数的方法,卜面讲述如何讣操作系统来创建能够执行线程函 数的线程。6.4 CreateThread 函数前面己经讲述了调用CreateProcess函数时如何创建进程

16、的主线程。如果想 要创建一个或多个辅助函数,只需要让一个已经在运行的线程来调用 CreateThread:HANDLE CreateThread(PSECURITY_ATTRIBUTES psa,DWORD cbStack,PTHREAD_START_ROUTINE pfnStartAddr,PVOID pvParam,DWORD fdwCreate,PDWORD pdwThreadID);当CreateThread被调用时,系统创建一个线程内核对象。该线程内核对象 不是线程木身,而是操作系统用來管理线程的较小的数据结构。可以将线程内核对 象视为由关丁线程的统计信息组成的一个小型数据结构。这与进程和进程内核对彖 之间的关系是相同的。系统从进程的地址空间中分配内存,供线程的堆栈使用。新线程运行的进程环

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号