NET多线程编程

上传人:20****03 文档编号:165248511 上传时间:2021-02-01 格式:DOC 页数:17 大小:59.50KB
返回 下载 相关 举报
NET多线程编程_第1页
第1页 / 共17页
NET多线程编程_第2页
第2页 / 共17页
NET多线程编程_第3页
第3页 / 共17页
NET多线程编程_第4页
第4页 / 共17页
NET多线程编程_第5页
第5页 / 共17页
点击查看更多>>
资源描述

《NET多线程编程》由会员分享,可在线阅读,更多相关《NET多线程编程(17页珍藏版)》请在金锄头文库上搜索。

1、.NET多线程编程在.NET多线程编程这个系列我们将一起来探讨多线程编程的各个方面。在文的开始向大家介绍多线程的有关概念以及多线程编程的基础知识;在接下来的文章中,我将逐一讲述.NET平台上多线程编程的知识,诸如System.Threading命名空间的重要类以及方法,并就一些例子程序来做说明。一多任务和多线程引言早期的计算硬件十分复杂,但是操作系统执行的功能确十分的简单。那个时候的操作系统在任一时间点只能执行一个任务,也就是同一时间只能执行一个程序。多个任务的执行必须得轮流执行,在系统里面进行排队等候。由于计算机的发展,要求系统功能越来越强大,这个时候出现了分时操作的概念:每个运行的程序占有

2、一定的处理机时间,当这个占有时间结束后,在等待队列等待处理器资源的下一个程序就开始投入运行。注意这里的程序在占有一定的处理器时间后并没有运行完毕,可能需要再一次或多次分配处理器时间。那么从这里可以看出,这样的执行方式显然是多个程序的并行执行,但是在宏观上,我们感觉到多个任务是同时执行的,因此多任务的概念就诞生了。每个运行的程序都有自己的内存空间,自己的堆栈和环境变量设置。每一个程序对应一个进程,代表着执行一个大的任务。一个进程可以启动另外一个进程,这个被启动的进程称为子进程。父进程和子进程的执行只有逻辑上的先后关系,并没有其他的关系,也就是说他们的执行是独立的。但是,可能一个大的程序(代表着一

3、个大的任务),可以分割成很多的小任务,为了功能上的需要也有可能是为了加快运行的速度,可能需要同一时间执行多个任务(每个任务分配一个多线程来执行相应的任务)。举个例子来说,你正在通过你的web浏览器查看一些精彩的文章,你需要把好的文章给下载下来,可能有些非常精彩的文章你需要收藏起来,你就用你的打印机打印这些在线的文章。在这里,浏览器一边下载HTML格式的文章,一边还要打印文章。这就是一个程序同时执行多个任务,每个任务分配一个线程来完成。因此我们可以看出一个程序同时执行多个任务的能力是通过多线程来实现的。多线程VS多任务正如上面所说的,多任务是相对与操作系统而言,指的是同一时间执行多个程序的能力,

4、虽然这么说,但是实际上在只有一个CPU的条件下不可能同时执行两个以上的程序。CPU在程序之间做高速的切换,使得所有的程序在很短的时间之内可以得到更小的CPU时间,这样从用户的角度来看就好像是同时在执行多个程序。多线程相对于操作系统而言,指的是可以同时执行同一个程序的不同部分的能力,每个执行的部分被成为线程。所以在编写应用程序时,我们必须得很好的设计以 避免不同的线程执行时的相互干扰。这样有助于我们设计健壮的程序,使得我们可以在随时需要的时候添加线程。线程的概念线程可以被描述为一个微进程,它拥有起点,执行的顺序系列和一个终点。它负责维护自己的堆栈,这些堆栈用于异常处理,优先级调度和其他一些系统重

5、新恢复线程执行时需要的信息。从这个概念看来,好像线程与进程没有任何的区别,实际上线程与进程是肯定有区别的:一个完整的进程拥有自己独立的内存空间和数据,但是同一个进程内的线程是共享内存空间和数据的。一个进程对应着一段程序,它是由一些在同一个程序里面独立的同时的运行的线程组成的。线程有时也被称为并行运行在程序里的轻量级进程,线程被称为是轻量级进程是因为它的运行依赖与进程提供的上下文环境,并且使用的是进程的资源。在一个进程里,线程的调度有抢占式和非抢占的模式。在抢占模式下,操作系统负责分配时间给各个进程,一旦当前的进程使用完分配给自己的时间,操作系统将决定下一个占用时间的是哪一个线程。因此操作系统将

6、定期的中断当前正在执行的线程,将分配给在等待队列的下一个线程。所以任何一个线程都不能独占。每个线程占用的时间取决于进程和操作系统。进程分配给每个线程的时间很短,以至于我们感觉所有的线程是同时执行的。实际上,系统运行每个进程的时间有2毫秒,然后调度其他的线程。它同时他维持着所有的线程和循环,分配很少量的时间给线程。线程的切换和调度是如此之快,以至于感觉是所有的线程是同步执行的。调度是什么意思?调度意味着处理器存储着将要执行完时间的进程的状态和将来某个时间装载这个进程的状态而恢复其运行。然而这种方式也有不足之处,一个线程可以在任何给定的时间中断另外一个线程的执行。假设一个线程正在向一个文件做写操作

7、,而另外一个线程中断其运行,也向同一个文件做写操作。Windows 95/NT,UNIX使用的就是这种线程调度方式。在非抢占的调度模式下,每个线程可以需要多少时间就占用多少时间。在这种调度方式下,可能一个执行时间很长的线程使得其他所有需要的线程“饿死”。在处理机空闲,即该进程没有使用时,系统可以允许其他的进程暂时使用。占用的线程拥有对的控制权,只有它自己主动释放时,其他的线程才可以使用。一些I/O和Windows 3.x就是使用这种调度策略。在有些操作系统里面,这两种调度策略都会用到。非抢占的调度策略在线程运行优先级一般时用到,而对于高优先级的线程调度则多采用抢占式的调度策略。如果你不确定系统

8、采用的是那种调度策略,假设抢占的调度策略不可用是比较安全的。在设计应用程序的时候,我们认为那些占用时间比较多的线程在一定的间隔是会释放的控制权的,这时候系统会查看那些在等待队列里面的与当前运行的线程同一优先级或者更高的优先级的线程,而让这些线程得以使用。如果系统找到一个这样的线程,就立即暂停当前执行的线程和激活满足条件的线程。如果没有找到同一优先级或更高级的线程,当前线程还继续占有。当正在执行的线程想释放的控制权给一个低优先级的线程,当前线程就转入睡眠状态而让低优先级的线程占有。在多处理器系统,操作系统会将这些独立的线程分配给不同的处理器执行,这样将会大大的加快程序的运行。线程执行的效率也会得

9、到很大的提高,因为将线程的分时共享单处理器变成了分布式的多处理器执行。这种多处理器在三维建模和图形处理是非常有用的。需要多线程吗我们发出了一个打印的命令,要求打印机进行打印任务,假设这时候计算机停止了响应而打印机还在工作,那岂不是我们的停止手上的事情就等着这慢速的打印机打印?所幸的是,这种情况不会发生,我们在打印机工作的时候还可以同时听音乐或者画图。因为我们使用了独立的多线程来执行这些任务。你可能会对多个用户同时访问数据库或者web服务器感到吃惊,他们是怎么工作的?这是因为为每个连接到数据库或者web服务器的用户建立了独立的线程来维护用户的状态。如果一个程序的运行有一定的顺序,这时候采用这种方

10、式可能会出现问题,甚至导致整个程序崩溃。如果程序可以分成独立的不同的任务,使用多线程,即使某一部分任务失败了,对其他的也没有影响,不会导致整个程序崩溃。毫无疑问的是,编写多线程程序使得你有了一个利器可以驾奴非多线程的程序,但是多线程也可能成为一个负担或者需要不小的代价。如果使用的不当,会带来更多的坏处。如果一个程序有很多的线程,那么其他程序的线程必然只能占用更少的时间;而且大量的时间是用于线程调度的;操作系统也需要足够的内存空间来维护每个线程的上下文信息;因此,大量的线程会降低系统的运行效率。因此,如果使用多线程的话,程序的多线程必须设计的很好,否则带来的好处将远小于坏处。因此使用多线程我们必

11、须小心地处理这些线程的创建,调度和释放工作。多线程程序设计提示有多种方法可以设计多线程的应用程序。正如后面的文章所示,我将给出详细的编程示例,通过这些例子,你将可以更好的理解多线程。线程可以有不同的优先级,举例子来说,在我们的应用程序里面,绘制图形或者做大量运算的同时要接受用户的输入,显然用户的输入需要得到第一时间的响应,而图形绘制或者运算则需要大量的时间,暂停一下问题不大,因此用户输入线程将需要高的优先级,而图形绘制或者运算低优先级即可。这些线程之间相互独立,相互不影响。在上面的例子中,图形绘制或者大量的运算显然是需要站用很多的时间的,在这段时间,用户没有必要等着他们执行完毕再输入信息,因此

12、我们将程序设计成独立的两个线程,一个负责用户的输入,一个负责处理那些耗时很长的任务。这将使得程序更加灵活,能够快速响应。同时也可以使得用户在运行的任何时候取消任务的可能。在这个绘制图形的例子中,程序应该始终负责接收系统发来的消息。如果由于程序忙于一个任务,有可能会导致屏幕变成空白,这显然需要我们的程序来处理这样的事件。所以我必须得有一个线程负责来处理这些消息,正如刚才所说的应该触发重画屏幕的工作。我们应该把握一个原则,对于那些对时间要求比较紧迫需要立即得到相应的任务,我们因该给予高的优先级,而其它的线程优先级应该低于它的优先级。侦听客户端请求的线程应该始终是高的优先级,对于一个与用户交互的用户

13、界面的任务来说,它需要得到第一时间的响应,其优先级因该高优先级。二Thread类本节将向大家介绍.NET中的线程API,怎么样用C#创建线程,启动和停止线程,设置优先级和状态.在.NET中编写的程序将被自动的分配一个线程.让我们来看看用C#编程语言创建线程并且继续学习线程的知识。我们都知道.NET的运行时环境的主线程由Main ()方法来启动应用程序,而且.NET的编译程序有自动的垃圾收集功能,这个垃圾收集发生在另外一个线程里面,所有的这些都是后台发生的,让我们无法感觉到发生了什么事情。在这里默认的是只有一个线程来完成所有的程序任务,但是正如我们在第一篇文章讨论过的一样,有可能我们根据需要自己

14、添加更多的线程,让程序更好的协调工作。比如说我们的例子中,一个有用户输入的同时需要绘制图形或者完成大量的运算的程序,我们必须得增加一个线程,让用户的输入能够得到及时的响应,因为输入对时间和响应的要求是紧迫的,而另外一个线程负责图形绘制或者大量的运算。.NET 基础类库的System. Threading命名空间提供了大量的类和接口支持多线程。这个命名空间有很多的类,我们将在这里着重讨论Thread这个类。System.Threading.Thread类是创建并控制线程,设置其优先级并获取其状态最为常用的类。他有很多的方法,在这里我们将就比较常用和重要的方法做一下介绍:Thread. Start

15、():启动线程的执行;Thread.Suspend():挂起线程,或者如果线程已挂起,则不起作用;Thread.Resume():继续已挂起的线程;Thread.Interrupt():中止处于 Wait或者Sleep或者Join 线程状态的线程;Thread.Join():阻塞调用线程,直到某个线程终止时为止Thread.Sleep():将当前线程阻塞指定的毫秒数;Thread.Abort():以开始终止此线程的过程。如果线程已经在终止,则不能通过Thread.Start()来启动线程。通过调用Thread.Sleep,Thread.Suspend或者Thread.Join可以暂停/阻塞线程

16、。调用Sleep()和Suspend()方法意味着线程将不再得到CPU时间。这两种暂停线程的方法是有区别的,Sleep()使得线程立即停止执行,但是在调用Suspend()方法之前,公共语言运行时必须到达一个安全点。一个线程不能对另外一个线程调用Sleep()方法,但是可以调用Suspend()方法使得另外一个线程暂停执行。对已经挂起的线程调用Thread.Resume()方法会使其继续执行。不管使用多少次Suspend()方法来阻塞一个线程,只需一次调用Resume()方法就可以使得线程继续执行。已经终止的和还没有开始执行的线程都不能使用挂起。Thread.Sleep(int x)使线程阻塞x毫秒。只有当该线程是被其他的线程通过调用Thread.Interrupt()或者T

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 教学/培训

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