用Visual Basic.Net创建多线程应用程序

2008-04-09 04:42:57来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

  这篇文章假设读者已经拥有以下的编程经验:VB,Windows环境,基于事件的编程,基本的HTML和脚本知识。这篇文章是基于微软.NET的Beta2版本。

  VB.NET的其中一个最令人期待的特性是可以创建和管理线程。虽然在VB6的应用中,我们可以通过Win32 CreateThread API来创建一个多线程的应用,或者通过欺骗COM库在一个独立的线程中创建一个组件,不过这些技术都是难以调试和维护的。

  造成这些困难的主要原因是由于VB 6.0并不是用来处理多线程应用的,这样会导致访问违例和内存错误。不同的是,Common Language Runtime(CLR)是为多线程的环境设计的,实际上Services架构在基本委派体系中就暗中集成了这个功能。其实,通过使用System.Threading命名空间,Services架构还支持显式使用线程API。

  对于那些不熟悉线程的读者,这里简单介绍一下,它可让你的应用分成多个单元执行,这些单元都是被抢先型的操作系统(例如Windows 2000)分配在不同时间运行,并且拥有不同的优先权。根据线程的优先权和特别的调度算法,操作系统分配每个线程运行一段的时间,称为time slice。当这段time slice过去时,线程就会挂起并且放回到队列中,接着另一个线程又会被分配一段time slice运行。在线程挂起时,它的状态就会被保存下来,以便下一次可以由停下来的地方开始工作。CLR支持线程的方式是通过启动每个带有一个主线程的AppDomain,并且允许它创建多个工作线程,每个工作线程都拥有自己的例外处理和状态数据。

  在一个应用中使用超过一个线程的明显好处是你的应用看来正在同时执行几个任务,这是由于不同的线程都得到了CPU的运行时间。实际上,在一台拥有多个处理器的机器上,来自一个AppDomain的线程可分配在所有的处理器上运行,从而允许同时地运作。在分布式的应用时,这样可提升扩展性,因为更多的客户可以分享一个服务器上的CPU资源,而对于桌面的应用,例如电子表格和word等也能够从线程中得到好处,可执行后台的操作例如重新计算和打印。不过,在使用VB.NET写分布式的应用时,如何应用这个概念呢?

  对于初学者,在你建立分布式的应用时,实际上你已经使用了一个多线程的体系。这是由于应用服务,例如IIS、组件服务和SQL Server全部都是多线程的。例如,在客户端请求网页时,它们的请求被由IIS控制的工作线程运载。这些线程中的其中之一可能会执行一个ASP.NET页面,该页面会调用组件服务中的一个组件。组件应该被配置为作为Server应用运行,这样它就会被该应用的一个线程池中的一个线程执行。组件也可能使用一个数据库连接,该连接是由SQL Server引擎分配的工作线程池中得到的。结果是,多个用户请求网页,要初始化组件和访问数据库时,它们的活动并不是连续的,因此不会受到单线程执行的限制。

  由于你在分布式的应用中所写的大部分代码都是在中层执行的,因此有些情形你需要显式地创建线程。这些情形包括有长时间的操作,例如文件IO,数据库维护任务,在一个Windows服务应用中为多个客户服务,以及由一个Microsoft Message Queue监听信息。这里只是会为你介绍使用线程的一些基本点,要得到更多的信息和其它的例子你可以查看其它的文档。

  要注意的问题:由于操作系统要跟踪和确定线程的进度,因此线程的系统开销会比较大,因此你不应该在应用的任何地方都创建新的线程。由于必须为每个线程分配内存,太多的线程将会令整个系统的性能受到影响。此外,线程还会带来一些VB的开发者没有遇到过的问题,例如同步访问和同享资源。因此,你必须经过仔细考虑才加入多线程的支持。

  在下面的部分,我们将会讨论使用线程和线程池。
156
 使用线程

  用来创建和维护线程的基类是Thread。它拥有Start, Stop, Resume, Abort, Suspend和Join (wait for)等方法让你操纵线程,还可以通过如Sleep, IsAlive, IsBackground, Priority, ApartmentState和ThreadState等方法查询和设置线程状态。

  注意:要记住大部分的Thread成员都是虚成员,因此只可以由一个特定Thread类的实例访问。要维护一个特定的线程,你可以创建一个新的Thread类实例,或者通过CurrentThread属性得到当前Thread的一个引用。例外的是Sleep方法,它可让当前的线程挂起指定的毫秒数。

  为了启动一个新的线程,你必须指定一个入口以便开始执行该线程。要求是该方法(可以是一个对象上的方法或者是一个模块中的方法)没有参数,并且要定义为一个Sub过程。在同一个对象内,以一个独立的线程来执行一个方法也是可能的。

  例如,看以下的代码段。在这个例子中,Instructors类的GetPhotos方法在一个独立的线程上执行。这个方法(没有显示)向数据库查询全部的教师图象,并且将每幅图象以文件的方式保存下来,在这里,数据库访问和文件访问在一个分开的线程上执行。

Dim tPhoto As Thread
Dim tsStart As ThreadStart
Dim objIns As New Instructors

tsStart = New ThreadStart(AddressOf objIns.GetPhotos)
tPhoto = New Thread(tsStart)

tPhoto.Priority = ThreadPriority.BelowNormal
tPhoto.Name = "SavingPhotos"

tPhoto.Start()

' Wait for the started thread to become alive
While (tPhoto.ThreadState = ThreadState.Unstarted)
 Thread.Sleep(100)
End While

...

If tPhoto.IsAlive Then
 MsgBox("Still processing images...")
 MsgBox("Waiting to finish processing images...")
 tPhoto.Join
End If

MsgBox("Done processing images.")
  在上面的代码中,你可以看到启动一个线程包括实例化一个ThreadStart委派,并且通过AddressOf操作符将入口地址传送给它。该委派然后就会传送给Thread类的构造器。在线程真正开始执行前,优先权被设置为BelowNormal,这样主线程将可更迅速地响应请求。虽然Win32 API支持30个优先权级别,不过在ThreadPriority枚举中,你只有4个其它的优先级可以设置 (AboveNormal, Highest, Lowest和Normal) 。

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:在VB.NET中使用抽象类

下一篇:与Visual Basic .NET一起使用.NET Framework