ImageVerifierCode 换一换
格式:DOCX , 页数:15 ,大小:23.23KB ,
资源ID:12869584      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/12869584.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(VBNET多线程程详细说明.docx)为本站会员(b****0)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

VBNET多线程程详细说明.docx

1、VBNET多线程程详细说明VB?.NET多线程编程的详细说明介绍 传统的Visual Basic开发人员已经建立了同步应用程序,在这些程序中事务按顺序执行。尽管由于多个事务多多少少地同时运行使多线程应用程序效率更高,但是使用先前版本的Visual Basic很难建立这类程序。 多线程程序是可行的,因为操作系统是多任务的,它有模拟同一时刻运行多个应用程序的能力。尽管多数个人计算机只有一个处理器,但是现在的操作系统还是通过在多个执行代码片断之间划分处理器时间提供了多任务。线程可能是整个应用程序,但通常是应用程序可以单独运行的一个部分。操作系统根据线程的优先级和离最近运行的时间长短给每一个线程分配处

2、理时间。多线程对于时间密集型事务(例如文件输入输出)应用程序的性能有很大的提高。 但是也有必须细心的地方。尽管多线程能提高性能,但是每个线程还是需要用附加的内存来建立和处理器时间来运行,建立太多的线程可能降低应用程序的性能。当设计多线程应用程序时,应该比较性能与开销。 多任务成为操作系统的一部分已经很久了。但是直到最近Visual Basic程序员才能使用无文档记录特性(undocumented)或者间接使用COM组件或者操作系统的异步部分执行多线程事务。.NET框架组件为开发多线程应用程序,在System.Threading名字空间中提供了全面的支持。 本文讨论多线程的好处以及怎样使用Vis

3、ual Basic .NET开发多线程应用程序。尽管Visual Basic .NET和.NET框架组件使开发多线程应用程序更容易,但是本文作了调整使其适合高级读者和希望从早期Visual Basic转移到Visual Basic .NET的开发人员。 多线程处理的优点 尽管同步应用程序易于开发,但是它们的性能通常比多线程应用程序低,因为一个新的事务必须等待前面的事务完成后才能开始。如果完成某个同步事务的时间比预想的要长,应用程序可能没有响应。多线程处理可以同时运行多个过程。例如,字处理程序能够在继续操作文档的同时执行拼写检查事务。因为多线程应用程序把程序分解为独立的事务,它们能通过下面的途径

4、充分提高性能: l 多线程技术可以使程序更容易响应,因为在其它工作继续时用户界面可以保持激活。 l 当前不忙的事务可以把处理器时间让给其它事务。 l 花费大量处理时间的事务可以周期性的把时间让给其它的事务。 l 事务可以在任何时候停止。 l 可以通过把单独事务的优先级调高或调低来优化性能。 明确地建立多线程应用程序的决定依赖于几个因素。多线程最适合下面的情况: l 时间密集或处理密集的事务妨碍用户界面。 l 单独的事务必须等待外部资源,例如远程文件或Internet连接。 例如,某个应用程序跟随Web页面上的链接并下载符合特定条件的文件。这种应用程序可以同步一个接一个地下载文件或者使用多线程在

5、同一时刻下载多个文件。多线程的方法比同步方法的效率高得多,因为即使某些线程从远程Web服务器上接收到的响应很慢,文件也可以被下载。 建立新线程 建立线程的最直接的方法是建立线程类的一个新的实例并且使用AddressOf语句替你希望运行的过程传递一个委托。例如下面的代码运行一个作为单独的线程的叫做SomeTask的子过程。 Thread1.Start 这儿的代码立即运行这就是建立和启动线程的全部工作。调用线程的Start方法后面的任何代码立即执行,不需要等待前面线程的结束。 下表是你能使用的控制单独线程的方法: 上面的大多数方法字面上容易理解,但是安全点(safe point)的概念对你来说可能

6、是新的。安全点是代码中的某个位置,在这个位置通用语言运行时可以安全地执行自动无用单元收集(garbage collection,释放无用变量并恢复内存的过程)。当调用线程的Abort或Suspend方法时,通用语言运行时分析代码,决定线程停止运行的适当位置。 下表是线程的一些常用的属性: 当建立和管理线程时它的属性和方法很重要。本文的线程同步部分将讨论你怎样使用这些属性和方法控制和调整线程。 线程参数和返回值 前面例子中的线程调用没有参数和返回值。这是使用这种方法建立和运行线程的主要缺点之一。但是,你可以在类或结构体中包装线程,为运行在单独线程上的过程提供和返回参数。 Class TasksC

7、lass Friend StrArg As String Friend RetVal As Boolean Sub SomeTask() StrArg字段是一个参数 MsgBox(The StrArg contains the string & StrArg) RetVal = True 设置返回参数中的返回值 End Sub End Class 为了使用这个类,设置存储参数的属性或者字段,接着异步调用需要的方法 Sub DoWork() Dim Tasks As New TasksClass() Tasks.StrArg = Some Arg 设置作为参数使用的字段 Thread1.Star

8、t() 启动新线程 Thread1.Join() 等待线程1结束 显示返回值 MsgBox(Thread 1 returned the value & Tasks.RetVal) End Sub手工建立和管理线程最适合于希望很好地控制细节(例如线程的优先级和线程模型)的应用程序。你可能想象,通过这种方法管理大量的线程是很困难的。在你需要很多线程时考虑使用线程池来减小复杂程度。 线程池 线程池是多线程的一种形式,在它里面,事务被添加到一个队列,并随着线程的建立自动启动。有了线程池,你使用希望运行的过程的委托调用Threadpool.QueueUserWorkItem方法,Visual Basic

9、 .NET就建立线程并运行该过程。下面的例子演示了怎样使用线程池启动几个事务: Sub DoWork() 对一个事务排队 对另一个事务排队End Sub当你需要启动很多单独事务而不需要单独设置每个线程的属性时,线程池是很有用的。每个线程使用默认的栈大小和优先级启动。默认情况下,每个系统处理器可以运行高达25个线程池线程。超过限制的线程可以排队,但是直到其它线程结束才能启动。 线程池的一个优点是你能把状态对象中的参数传递给每个事务过程。如果调用的过程需要一个以上参数,你可以把一个结构体或类的示例转换为Object数据类型。 参数和返回值 从线程池线程返回值有点棘手。从函数调用返回值的标准方法在这

10、儿是不允许的,因为Sub过程是能被线程池排队的唯一过程类型。提供参数和返回值的途径是把这些参数,返回值和方法包装进一个包装类。提供参数和返回值的一个更简单的方法是使用QueueUserWorkItem方法的ByVal状态对象变量。如果使用该变量传递引用给类的一个实例,实例中的成员能被线程池线程修改并作为返回值使用。起先可以修改值传递的变量所引用的对象是不明显的,由于只有对象引用被值传递了,它才是可能的。当你修改对象引用引用的对象的成员时,改变应用到实际类的实例。 结构体不能用于在状态对象内部返回值。因为结构体是值类型的,异步处理做的改变不会改变原结构体的成员。当不需要返回值时使用结构体提供参数

11、。 Friend Class StateObj Friend StrArg As String Friend IntArg As Integer Friend RetVal As StringEnd ClassSub ThreadPoolTest() Dim StObj1 As New StateObj() Dim StObj2 As New StateObj() 设置状态对象中的作为参数的一些字段 StObj1.IntArg = 10 StObj1.StrArg = Some string StObj2.IntArg = 100 StObj2.StrArg = Some other stri

12、ng 对一个事务进行排队 (AddressOf SomeOtherTask), StObj1) 对另一个事务进行排队 (AddressOf AnotherTask), StObj2)End SubSub SomeOtherTask(ByVal StateObj As Object) 使用状态对象字段作为参数 Dim StObj As StateObj StObj = CType(StateObj, StateObj) 转换成正确的类型 MsgBox(StrArg contains the string & StObj.StrArg) MsgBox(IntArg contains the num

13、ber & CStr(StObj.IntArg) 使用一个字段作为返回值 StObj.RetVal = Return Value from SomeOtherTaskEnd SubSub AnotherTask(ByVal StateObj As Object) 使用状态对象作为参数。状态对象作为Object传递。把它转换为特定类型使使用更容易 Dim StObj As StateObj StObj = CType(StateObj, StateObj) MsgBox(StrArg contains the String & StObj.StrArg) MsgBox(IntArg contai

14、ns the number & CStr(StObj.IntArg) 使用一个字段作为返回值 StObj.RetVal = Return Value from AnotherTaskEnd Sub通用语言运行时自动为排队的线程池事务建立线程,当这些事务完成时释放这些资源。一旦事务被排队了,这就不是取消事务的容易的方法了。ThreadPool线程使用多线程单元(MTA)线程模型运行。如果你希望线程使用单线程单元模型(STA)运行,必须手工建立线程。 线程同步 同步提供了多线程编程的无组织特性和同步处理的有组织次序之间一种折衷的方法。使用同步技术能够达到的目标: l 在事务必须按特定次序执行的时候

15、,明确地控制代码运行的次序。 l 当两个线程在同一时刻共享相同的资源的时候防止错误的发生。 例如,你可以使用同步来引发一个显示过程等待另一个线程上运行的数据检索过程结束。 有两种同步的途径,轮询(polling)和使用同步对象。轮询是从某个循环中周期性地检查异步调用的状态。轮询是管理线程的效率最低的方法,因为它周期性检查多样线程属性的状态,浪费了资源。 你可以想象,轮询为了换取对线程次序的控制牺牲了多线程的一些优点。效率更高的途径是使用Join方法控制线程。Join引发调用过程等待一个线程完成或者超时(如果指定了超时值)。Join这个名字基于建立新线程,它是执行路径中的分叉。你使用Join方法

16、把单独的执行路径合并成单个线程。 图1.线程 有一点必须清楚,Join是同步的或阻塞的调用。一旦你调用Join或等待句柄的等待方法,调用过程会停止并等待线程发出完成信号。 Sub JoinThreads() Thread1.Start() Thread1.Join() 等待该线程结束 MsgBox(Thread is done)End Sub这些简单的控制线程的方法对管理少量的线程是有用的,但是在大型项目中使用困难。下一部分讨论用于同步的一些高级技术。 高级同步技术 多线程应用程序通常使用等待处理和监视对象来同步多个线程。下表是.NET框架组件中能用于同步线程的一些类: 等待句柄 等待句柄是把

17、某个线程的状态信号发送给另一个线程的对象。当线程需要独占访问某种资源时,它们可以使用等待句柄通知其它线程。其它线程必须等待这些资源,直到等待句柄不再使用。等待句柄有两种状态:signaled和nonsignaled。不属于任何线程的等待句柄状态为signaled。属于某个线程的等待句柄的状态是nonsignaled。 线程通过调用一个等待方法(例如WaitOne、 WaitAny或 WaitAll)来请求等待句柄的所有权。等待方法也是阻塞调用,与独立线程的Join方法类似。 l 如果其它线程没有拥有等待句柄,该调用立即返回True,等待线程的状态变为nonsignaled,拥有等待句柄的线程继

18、续运行。 l 如果某个线程调用等待句柄的一个等待方法,但是等待句柄属于另一个线程,发出调用的线程要么等待一个特定时间(如果指定了超时值)或者等待不确定的时长(没有指定超时值)直到其它线程释放等待句柄。如果设置了超时值并且等待句柄在期满前被释放了,该调用将返回True。否则,该调用返回False,发送调用的线程继续运行。 当拥有等待句柄的线程完成后或者它们再也不需要等待句柄时,它们调用Set方法。其它线程可以通过调用Reset方法或WaitOne、WaitAll、 WaitAny把等待句柄的状态复位成nonsignaled,并且成功地等待某个线程调用Set。当某个等待线程被释放后系统自动把Aut

19、oResetEvent句柄复位成nonsignaled。如果没有线程在等待,该事件对象的状态仍然为signaled。 Visual Basic .NET中通常使用三类等待句柄:互斥对象、ManualResetEvent和AutoResetEvent。后两种通常用于同步事件。 互斥对象 互斥对象都是同步对象,它们只能在一个时刻由一个线程拥有。实际上,互斥这个名字衍生自互斥对象的所有权是相互排斥的。当线程请求独占访问某种资源时,它们请求互斥对象的所有权。因为在某个时刻只有一个线程能拥有一个互斥对象,其它线程在使用资源前必须等待互斥对象的所有权。 WaitOne方法引发一个调用线程等待互斥对象的所有

20、权。如果拥有互斥对象的线程正常终止,该互斥对象的状态就被设置为signaled,下一个线程获得它的所有权。 同步事件 同步事件用于通知其它的线程发生了某种事情或者某种资源可用。不要被它使用了事件这个词迷惑了。同步事件与其它的Visual Basic事件不同,它是真正的等待句柄。与其它的等待句柄类似,同步事件有两种状态signaled 和nonsignaled。调用同步事件的某个等待方法的线程必须等待,直到其它线程调用Set方法给事件发信号。有两个同步事件类。线程使用Set方法把ManualResetEvent实例的状态设置为signaled。线程使用Reset方法或控制返回等待WaitOne调

21、用把实例的状态设置为nonsignaled。AutoResetEvent类的实例也可以使用Set设置为signaled,但是只要通知等待线程事件变为signaled,它们自动返回到nonsignaled。 下面的例子使用AutoResetEvent类同步线程池事务。 Sub StartTest() Dim AT As New AsyncTest() AT.StartTask()End SubClass AsyncTest Sub StartTask() Dim arg As String = SomeArg AddressOf Task), arg) 对一个事务进行排队 AsyncOpDone

22、.WaitOne() 等待该线程调用Set MsgBox(Thread is done.) End Sub Sub Task(ByVal Arg As Object) MsgBox(Thread is starting.) MsgBox(The state object contains the string & CStr(Arg) AsyncOpDone.Set() 发信号表明该线程完成了 End SubEnd Class监视对象和同步锁 监视对象确保代码块的运行不被运行在其它线程中的代码打断。换句话说,其它线程中的代码不能运行,直到被同步的代码块结束。在Visual Basic .NET中

23、使用SyncLock关键字来简化监视对象的访问。在Visual C# .NET中使用Lock关键字。 例如,假定你有一个程序,它重复地、异步读取数据并显示结果。使用优先多任务操作系统,正在运行的线程可以因为操作系统允许其它的线程运行而被打断。如果没有同步,数据正在显示时,显示数据的对象被其它的线程修改,有可能得到的是部分更新的数据视图。SyncLock保证一段代码持续运行,不被打断。下面的例子显示了怎样使用SyncLock给显示过程提供数据对象的独占访问。 Class DataObject Public ObjText As String Public ObjTimeStamp As Date

24、End ClassSub RunTasks() Dim MyDataObject As New DataObject() ReadDataAsync(MyDataObject) SyncLock MyDataObject DisplayResults(MyDataObject) End SyncLockEnd SubSub ReadDataAsync(ByRef MyDataObject As DataObject) 添加异步读取和处理数据的代码End SubSub DisplayResults(ByVal MyDataObject As DataObject) 添加显示结果的代码End Su

25、b当有一段代码不能被某个独立的线程中运行的代码打断时使用SyncLock。 Interlocked类 你可以使用Interlocked类的方法防止多个线程同时更新或比较同一个值的问题发生。这个类的方法让你安全地增加、减少、交换和比较来自任何线程的值。下面的例子演示了怎样使用Increment方法增加一个运行在独立线程上的多个过程共享的变量的值。 Sub ThreadA(ByRef IntA As Integer)End SubSub ThreadB(ByRef IntA As Integer)End SubReaderWriter锁 在有些情况下,你可能希望只在写数据时锁定资源,在数据没有更新

26、完前允许多个客户同时读数据。某个线程正在修改资源时,ReaderWriterLock类加强了对该资源的独占访问,但是允许读取资源的非独占访问。ReaderWriter锁是排他锁的一个有用的备选方案,排他锁引起其它线程等待,即使这些线程不需要更新数据。下面的例子演示了怎样使用ReaderWriter调整来自多个线程的读和写操作。 Class ReadWrite ReadData和WriteData方法可以被多个线程安全地调用Sub ReadData() 这个过程从数据源读取信息。在允许其它线程调用ReadData时,读取锁放置任何数据写入直到读取完成 Try 此处执行数据操作 Finally R

27、eadWriteLock.ReleaseReaderLock() 释放读取锁 End Try End Sub Sub WriteData() 这个过程向数据源写信息。写入锁防止数据被读取或者写入知道线程完成写操作。 Try 此处执行写操作 Finally ReadWriteLock.ReleaseWriterLock() 释放写入锁 End Try End SubEnd Class死锁 在多线程应用程序中线程同步是无价之宝,但是始终有多个线程彼此等待的死锁的危险。类似汽车停在四条路上,彼此等待对方前进,死锁使所有动作停止。不用说,避免死锁很重要。有很多种途径会造成死锁,同样有多种方法可以避免它

28、们。尽管本文没有足够的篇幅讨论死锁相关的问题,但是重要的一点是细心计划是避免死锁的关键。你可以在开始编码前用图解法表示应用程序,预计死锁的情形。 线程计时器 Threading.Timer类对于在独立的线程上周期性地运行事务是很有用的。例如,你可以使用线程计时器检查数据库的状态和完整性或者备份关键文件。下面的例子每两秒启动一个事务,并使用一个标记来初始化停止计时器的Dispose方法。这个例子把状态发送到输出窗口,因此在测试代码前你可以通过按Control+Alt+O使窗口可见。 Class StateObjClass 为TimerTask调用保持参数 Public SomeValue As

29、Integer Public TimerCanceled As BooleanEnd ClassSub RunTimer() Dim StateObj As New StateObjClass() StateObj.TimerCanceled = False StateObj.SomeValue = 1 Dim TimerDelegate As New Threading.TimerCallback(AddressOf TimerTask) 建立一个定时器每2秒调用一个过程。注意:这儿没有Start方法,计时器在实例被建立时启动它 StateObj.TimerReference = Timer

30、Item 为Dispose保存一个引用 While StateObj.SomeValue 10 执行10次 End While StateObj.TimerCanceled = True 请求计时器对象的DisposeEnd SubSub TimerTask(ByVal StateObj As Object) Dim State As StateObjClass = CType(StateObj, StateObjClass) Dim x As Integer 使用interlocked类增加计数器变量的值 Debug.WriteLine(Launched new thread & Now)

31、If State.TimerCanceled Then 请求Dispose Debug.WriteLine(Done & Now) End IfEnd Sub取消事务 多线程的优点之一是应用程序的用户界面保持响应时,事务可以在其它的线程上运行。同步事件和作为标记的字段通常用于通知其它线程你希望停止它。下面的例子使用同步事件取消一个事务。为了使用这个例子,给项目添加下面的模块。调用StartCancel.StartTask()启动一个线程,调用StartCancel.CancelTask()取消一个或多个正在运行的线程。 Module StartCancel Private Sub SomeLongTask() Dim Lo

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1