VB.NET多线程应用
创始人
2024-02-09 06:23:24
0

开发者一直要求微软为VB加入更多的多线程功能,对于VB.NET也是这样。VB6已经支持建立多线程的EXE、DLL和OCX。不过使用多线程这个词语,可能也不太确切。因此VB6仅支持运行多个单线程的单元。一个单元实际上是代码执行的空间,而单元的边界限制了代码访问任何单元以外的事物。

VB.NET就不同了,它支持建立自由线程(free-threaded)的应用。这意味着多个线程可以访问同样一套的共享数据。本文的以下部分将讨论一下多线程的一些基本点。

问题

虽然VB6支持多个单线程的单元,不过它并不支持一个自由线程的模型,即不允许多个线程使用同一套数据。在许多的情况下,你需要建立一个新的线程来进行后台的处理,这样可提高应用的可用性,否则,一个长的处理就可以令程序的响应变得很慢,例如你按下表格上的一个取消按钮,却很久都没有响应。

解决办法

由于VB.NET使用了CLR(Common Language Runtime),从而拥有了许多的新特性,其中的一个是可以创建自由线程的应用。

使用线程

在VB.NET中,运用线程是很简单的。我们将在后面涉及其中的细节,现在我们首先来创建一个简单的表格,它使用一个新的线程来运行一个后台处理。第一件要做的事情是创建运行在新线程上的后台任务。以下的代码执行一个相当长的运行处理--一个无限的循环:

Private Sub BackgroundProcess()

Dim i As Integer = 1

Do While True

ListBox1.Items.Add("Iterations: " + i)

i += 1

Loop

End Sub

这段代码无限地循环,并且在每次执行时为表格上的一个列表框加入一个项目。如果你对VB.NET不熟悉的话,你将会发现这段代码和VB6的有一些区别:

. 在声明变量Dim i As Integer = 1时赋值

. 使用+=操作符i += 1代替i = i + 1

. 没有使用Call关键字

一旦我们拥有了一个工作的处理,我们就需要将这段代码分配给一个线程处理,并且启动它。为此我们要使用线程对象(Thread object),它是.NET架构类中System.Threading命名空间的一部分。在实例化一个新的线程类时,我们将要在线程类构造器执行的代码块的一个引用传送给它。以下的代码创建一个新的线程对象,并且将BackgroundProcess的一个引用传送给它:

Dim t As Thread

t = New Thread(AddressOf Me.BackgroundProcess)

t.Start()

AddressOf操作符创建了一个到BackgroundProcess方法的委派对象。在VB.NET中,一个委派是一个类型安全、面向对象的函数指针。在实例化该线程后,你可以通过调用线程的Start()方法来开始执行代码。

控制线程

在线程启动后,你可以通过线程对象的一个方法来控制它的状态。你可以通过调用Thread.Sleep方法来暂停一个线程的执行,这个方法可以接收一个整型值,用来决定线程休眠的时间。拿前面的例子来说,如果你想让列表项目增加的速度变慢,可以在其中放入一个sleep方法的调用:

Private Sub BackgroundProcess()

Dim i As Integer = 1

Do While True

ListBox1.Items.Add("Iterations: " + i)

i += 1

Thread.CurrentThread.Sleep(2000)

Loop

End Sub

CurrentThread是一个public static的属性值,可让你得到当前运行线程的一个引用。

你还可以通过调用Thread.Sleep (System.Threading.Timeout.Infinite)来让线程进入休眠状态,有点特别的是,这个调用的休眠时间是不确定的。要中断这个休眠,你可以调用Thread.Interrupt方法。

与休眠和中断类似的是挂起和恢复。挂起可让你暂停一个线程,直到另一个线程调用Thread.Resume为止。休眠和挂起的区别是,后者并不立刻让线程进入一个等待的状态,线程并不会挂起,直到.NET runtime认为现在已经是一个安全的地方来挂起它了,而休眠则会立刻让线程进入一个等待的状态。

最后要介绍的是Thread.Abort,它会停止一个线程的执行。在我们的那个简单例子中,如果要加入一个按钮来停止处理,很简单,我们只要调用Thread.Abort方法就行了,如下所示:

Private Sub Button2_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Button2.Click

t.Abort()

End Sub

这就是多线程的强大之处。用户界面的响应很好,因为它运行在一个单独的线程中,而后台的处理运行在另外一个线程中。在用户按下取消按钮时,便会马上得到响应,并且停止处理。

上面的例子只是一个相当简单的应用。在编程时,你还需要使用到多线程的许多复杂特性。其中的一个问题是如何将程序的数据由线程类的构造器传入或者传出,也就是说,对于放到另外一个线程中的过程,你既不能传参数给它,也不能由它返回值。这是由于你传入到线程构造器的过程是不能拥有任何的参数或者返回值的。为了解决这个问题,可以将你的过程封装到一个类中,这样方法的参数就可使用类中的字段。

这里我们举一个简单的例子,如果我们要计算一个数的平方,即:

Function Square(ByVal Value As Double) As Double

Return Value * Value

End Function

为了在一个新的线程中使用这个过程,我们将它封装到一个类中:

Public Class SquareClass

Public Value As Double

Public Square As Double

Public Sub CalcSquare()

Square = Value * Value

End Sub

End Class

使用这些代码来在一个新的线程上启动CalcSquare过程,如下所示:

Private Sub Button1_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Button1.Click

Dim oSquare As New SquareClass()

t = New Thread(AddressOf oSquare.CalcSquare)

oSquare.Value = 30

t.Start()

End Sub

要注意到,在线程启动后,我们并没有检查类中的square值,因为即使你调用了线程的start方法,也不能确保其中的方法马上执行完。要从另一个线程中得到值,有几个方法,这里使用的方法是最简单的,即是在线程完成的时候触发一个事件。我们将在后面的线程同步中讨论另一个方法。以下的代码为SquareClass加入了事件声明。

Public Class SquareClass

Public Value As Double

Public Square As Double

Public Event ThreadComplete(ByVal Square As Double)

Public Sub CalcSquare()

Square = Value * Value

RaiseEvent ThreadComplete(Square)

End Sub

End Class

在调用代码中捕捉事件的方法和VB6差不多,你仍然要声明WithEvents变量,并且在一个过程中处理事件。有些不同的是,你声明处理事件的过程使用的是Handles关键字,而不是通过VB6中通常使用的Object_Event。

Dim WithEvents oSquare As SquareClass

Private Sub Button1_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Button1.Click

oSquare = New SquareClass()

t = New Thread(AddressOf oSquare.CalcSquare)

oSquare.Value = 30

t.Start()

End Sub

Sub SquareEventHandler(ByVal Square As Double) _

Handles oSquare.ThreadComplete

MsgBox("The square is " & Square)

End Sub

对于这种方法,要注意的是处理事件的过程,在这个例子中的是SquareEventHandler,将运行在产生该事件的线程中。它并不是运行在表格执行的线程中。

同步线程

在线程的同步方面,VB.NET提供了几个方法。在上面的平方例子中,你要与执行计算的线程同步,以便等待它执行完并且得到结果。另一个例子是,如果你在其它线程中排序一个数组,那么在使用该数组前,你必须等待该处理完成。为了进行这些同步,VB.NET提供了SyncLock声明和Thread.Join方法。

SyncLock可得到一个对象引用的唯一锁,只要将该对象传送给SyncLock就行了。通过得到这个唯一锁,你可以确保多个线程不会访问共享的数据或者在多个线程上执行的代码。要得到一个锁,可使用一个较为便利的对象--与每个类关联的System.Type对象。System.Type对象可通过使用GetType方法得到:

Public Sub CalcSquare()

SyncLock GetType(SquareClass)

Square = Value * Value

End SyncLock

End Sub

另一个是Thread.Join方法,它可让你等待一个特定的时间,直到一个线程完成。如果该线程在你指定的时间前完成了,Thread.Join将返回True,否则它返回False。在平方的例子中,如果你不想使用触发事件的方法,你可以调用Thread.Join的方法来决定计算是否完成了。代码如下所示:

Private Sub Button1_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Button1.Click

Dim oSquare As New SquareClass()

t = New Thread(AddressOf oSquare.CalcSquare)

oSquare.Value = 30

t.Start()

If t.Join(500) Then

MsgBox(oSquare.Square)

End If

End Sub

对于这种方法,要注意的是处理事件的过程,在这个例子中的是SquareEventHandler,将运行在产生该事件的线程中。它并不是运行在表格执行的线程中。

相关内容

热门资讯

原创 魔... 盘点魔兽世界60版本黑上足以称神的5大极品装备,敢问各位大兄弟是否曾经拥有过?速看! 一:恶魔之击 ...
原创 崩... 《崩坏星穹铁道》4.5版本将复刻五星雷属性巡猎角色不死途,她主要围绕追击体系展开,既能承担队伍主C的...
前《铁拳8》总监加入原田胜弘新... 前《铁拳》系列负责人原田胜弘在离开万代南梦宫后,拉上了同样作为《铁拳》核心开发者之一的米盛祐一一起加...
原创 辅... 国服英雄战力榜,目前也就剩下一个辅助了,本文就来跟大家分析一下,对比8月2日我分享的数据,哪些英雄的...
病娇机甲少女!极端“恋爱模拟”... 如果拯救末世的代价是最依赖你的她,你还会陪在她身边吗? 《少女机师养成计划:女武神协议》是一款类似《...
乐高哈利·波特25年,哪款18... 今年的乐高“重返霍格沃茨”活动,很快又要迎来一款大体量新品。 乐高哈利·波特 76476 魔法部 –...
崩铁 x 大白兔联动!风堇、那... 星穹铁道4.5版本“挥掷千星的筹码”前瞻官宣了即将开启的联动,分别是大白兔奶糖和《绝区零》。不少崩铁...
《仁王3》DLC“庆安地狱变”... “‘仁王’系列始终不变的优势,在于高速爽快的动作体验。” Team NINJA旗下最为标志性的ARP...
《多洛可小镇》:从零开始的末日... 撰文:无铭 图片:《多洛可小镇》Steam 商店页截截图 前言 你是否想象过在末日废土世界中身体力行...
机构估算《GTA 6》预购收入... IT之家 8 月 19 日消息,大家都知道《GTA 6》很可能会打破各种纪录,但现在,围绕这款游戏的...
原创 从... 典韦这个英雄,无愧狂战士之名,形象到打法都突出一个狂野,而他的皮肤,越能契合这个特性,似乎就越能得到...
温柔强大的女孩子,居然有如此疯... 佩丽卡——她算是姬短暂的《明日方舟终末地》冒险中最喜欢的一个角色了,虽然当时她可能不如莱万汀那般输出...
盗墓笔记“联姻”逆水寒?七夕直... 马上就是七夕佳节,就在大家都沉浸在即将到来的甜蜜氛围时,网易旗下《逆水寒》手游趁着今天8月17日稻米...
逆水寒官宣《盗墓笔记》,一个 ... 每年8月17日,网络圈层总会迎来一场专属狂欢,这就是属于千万“稻米”的专属庆典——稻米节。 目前,...
《首都高赛车》制作组采访 时隔... 时隔近二十年,由日本游戏开发商元气(Genki)重启的经典赛车游戏《首都高赛车》新作已于去年推出。本...
「国服出装」“半球流”亚连彻底... 这一篇文章让我们来看一下40位国服亚连的出装铭文汇总。 推荐出装铭文 影忍之足,闪电匕首,红...
ENC延期人员或有变动,Bin... LPL第三赛段精彩赛事依旧在火热进行中,明天西安主场的对决就要开始了,常规赛最后一周,还是挺让人期待...
从561个作品看一场游戏黑客松... 朱 敏 腾讯研究院研究员 胡 璇 腾讯研究院高级研究员 今年夏天,一支三人小队用三天做出了第一版游戏...
主台度假,副台渡劫?崩铁4.5... 近日,《崩坏:星穹铁道》在4.5版本前瞻里整了一手大活儿。在8月14日前瞻当天,崩铁官号在同一时间开...
原创 明... 8月15日,网易举办《天下》18周年玩家生态大会。除了游戏本身的迭代升级、周年福利,息影22年的王祖...