代码改变世界

C# 线程手册 第一章 线程定义

2011-12-30 10:55  DanielWise  阅读(5196)  评论(15编辑  收藏  举报

概要

多线程是一种将一个应用程序切分成“线程”并按步骤运行程序的其他部分的平台开发能力。在大多数编程语言中,你会有一个Main()方法,每行代码都会顺序执行,只有当前面的一行代码执行完,后面的代码才会执行。线程是操作系统常规多任务能力的一个组成部分并允许应用程序的一部分与其他对象的分别执行的一个特定对象,所以不在应用程序通用执行顺序范畴内。在这一章,我们将讨论多任务的不同类型。

另外一个概念是自由线程, 它对于大多数C++或者Java程序员来说已经很熟悉了;我们将定义这个概念并进一步讨论在C#中是如何实现的并将简要比较自由线程模型和其他模型,比如Visual Basic 6.0 的apartment-threading 模型。我们不打算在这上面浪费太多笔墨,因为这不是一本历史书同时这本书也不是关于Visual Studio 6.0的。然而理解是什么将这些模型分开将会帮助你理解自由线程技术的曼妙。这一章的内容是帮助你理解本书余下部分的基础,从本章你将学到(不保证学会):

1. 从概念上讲,什么是线程?

2. 多种多任务和线程模型的比较。

3. 线程在哪?它们是如何分配处理器时间的?

4. 如何使用中断和优先级控制并管理线程?

5. 应用程序域的概念,以及它们如何比一个简单的处理环境能向你的应用程序提供更好的安全性控制。

线程定义

在这一章的结尾,你将理解以下内容:

1. 什么是多任务?不同类型的多任务是什么样子的?

2. 什么是进程?

3. 什么是线程?

4. 什么是主线程?

5. 什么是子线程?

多任务

你可能知道,多任务的概念是指一个操作系统在同一段时间内运行多个应用程序的能力。例如,当你在读这篇文章时,微软Outlook 也在运行同时你还打开了两个word 文档,通过系统跟踪工具可以知道后台有更多程序在运行。当来回切换程序时,看起来它们好像同时运行,当然这里说的”程序“的概念有点模糊,事实上我们指的是进程。在下一章我们将会对”进程“做进一步介绍。

经典说法是多任务实际上有两种不同的类型。Windows 目前在线程中仅使用了其中的一种,我们将在本书中广泛探讨这种模式。然而,我们也要看看之前的多任务类型以便于我们可以理解这两种类型的不同以及采用当前方法的优势。

在Windows 的早期版本-比如Windows 3.x-以及其他操作系统中,只有当一个线程通过释放自己占用的处理器给其他正在运行的程序时,一个程序才被允许执行。因为它取决于应用程序与其他正在运行程序的合作,这种类型的多任务称作协作式多任务。这种类型的多任务的劣势是一旦一个程序没有释放处理器,那么其他应用程序将会被挂起。实际情况是正在运行的应用程序卡住了,其他应用程序排队等候。这跟在银行排队办业务很相似。每个柜台在同一时间只能服务一个客户。客户在他们的事务完成之前不可能从柜台窗口前离开。一旦完成了,柜台可以按顺序服务下一个人。它不在乎一个客户将要在窗口花费多长时间。即便一个人只想存一张支票,他也必须等待前面那个人的5个事务全部完成。

幸运的是,我们将不会在Windows 2000 和XP 以及它们之后的版本中碰到这个问题,因为与Windows之前版本使用的多任务方法完全不同了。操作系统在中断一个应用程序并允许其他应用程序执行之前会允许被中断程序执行一小段时间。这种多任务的中断类型成为”抢断式多任务“。“抢断式”简单的定义就是中断一个程序来允许另外一个程序执行。重点需要注意的是一个应用程序可能还没有完成它的任务,但是操作系统将要允许另外一个程序使用它的处理器时间。银行柜台的例子在这里就不适用了。在现实世界中,这就好比银行柜台中断了一个客户正在执行的业务然后允许其他客户开始他们的事务。这也不意味着下一个客户可以完成他们的事务。柜台可能会一个接一个用户的中断-最终服务到第一个客户。这很像人类大脑在处理社交和其他任务时候的表现。虽然抢断式多任务解决了处理器被锁住的问题,但它也有自己的问题,正如你所知道的那样,一些应用程序可能会共享数据库连接和文件等资源。如果两个应用程序在同一时间访问同样的资源会发生什么?一个程序可能把数据给改了,然后它被中断,允许另外一个程序来再一次改数据。现在两个程序修改了同一份数据。但两个程序都假定自己独占了数据。让我们来看图1中的一个简单场景。

image

图1

在步骤1,程序A从一个数据存储器获取一个整型值并把它放到内存中。这个整型变量被设置为10. 应用程序A然后被中断并强制等待程序B。步骤2开始,应用程序B获取同样的整型值10. 在步骤3, 应用程序B将这个值加1. 变量然后在步骤4被存储到内存中。在步骤5,应用程序A也增加这个值。然而,因为它们都在变量值为10时获取到对其的引用,所以在程序A设置完这个值以后它仍然为11. 而期待的结果是12. 这两个程序都不知道还有其他程序访问这个资源,最终它们同时尝试增加的值有了一个错误的结果。如果这发生在一个引用计数器或者一个负责订机票的客户端会怎么样?

这个问题与多任务抢占有关,而且已经通过同步的方法解决,具体会在第三章介绍。

进程

当一个程序运行了以后,内存以及其他资源都将分配给它。内存和资源的物理隔离称作一个进程。当然,一个程序可能会有不止一个进程。“程序”和“进程”并不是一个意思。分配给一个进程的内存与其他进程隔离而且只有自身可以访问。

在Windows操作系统中,你可以打开Windows 任务管理器来查看正在运行的进程。在任务栏的空白处单击右键然后选择任务管理器,打开的任务管理器包含三个选项卡(在最新的Windows 版本中,已经有不止三个选项卡了):应用程序,进程和性能。进程选项卡显示进程名,进程ID(PID), CPU使用率,进程到目前为止使用的处理器时间以及它正在使用的内存大小。为了便于理解,程序和进程分别有不同的选项卡。程序可能有多个进程。每个进程有它自己的数据,执行代码和系统资源。

image

下一篇我们将会继续介绍线程…