VB.NET多线程应用


开发者一直要求微软为VB加入更多的多线程功能,对于也是这样。VB6已经支持建立多线程的EXE、DLL和OCX。不过使用多线程这个词语,可能也不太确切。因此VB6仅支持运行多个单线程的单元。一个单元实际上是代码执行的空间,而单元的边界限制了代码访问任何单元以外的事物。
就不同了,它支持建立自由线程(free-threaded)的应用。这意味着多个线程可以访问同样一套的共享数据。本文的以下部分将讨论一下多线程的一些基本点。
问题
虽然VB6支持多个单线程的单元,不过它并不支持一个自由线程的模型,即不允许多个线程使用同一套数据。在许多的情况下,你需要建立一个新的线程来进行后台的处理,这样可提高应用的可用性,否则,一个长的处理就可以令程序的响应变得很慢,例如你按下表格上的一个取消按钮,却很久都没有响应。
解决办法
由于使用了CLR(Common Language Runtime),从而拥有了许多的新特性,其中的一个是可以创建自由线程的应用。
使用线程
在中,运用线程是很简单的。我们将在后面涉及其中的细节,现在我们首先来创建一个简单的表格,它使用一个新的线程来运行一个后台处理。第一件要做的事情是创建运行在新线程上的后台任务。以下的代码执行一个相当长的运行处理--一个无限的循环:
Private Sub BackgroundProcess()
Dim i As Integer = 1
Do While True
ListBox1.Items.Add("Iterations: " + i)
i += 1
Loop
End Sub
这段代码无限地循环,并且在每次执行时为表格上的一个列表框加入一个项目。如果你对不熟悉的话,你将会发现这段代码和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方法的委派对象。在中,一个委派是一个类型安全、面向对象的函数指针。在实例化该线程后,你可以通过调用线程的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,将运行在产生该事件的线程中。它并不是运行在表格执行的线程中。
同步线程
在线程的同步方面,提供了几个方法。在上面的平方例子中,你要与执行计算的线程同步,以便等待它执行完并且得到结果。另一个例子是,如果你在其它线程中排序一个数组,那么在使用该数组前,你必须等待该处理完成。为了进行这些同步,提供了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,将运行在产生该事件的线程中。它并不是运行在表格执行的线程中。


  • Vb.net,澶氱嚎绋,鏂扮嚎绋嬪惎鍔ㄥ悗,鐣岄潰鍝嶅簲鍙樻參,浣嗗彲浠ョ浉搴,鎬庝箞瑙e喅?_鐧...
    绛旓細浠ヤ笅鏄湪澶氱嚎绋涓樉绀鸿繘搴︽潯浠g爜 '瀹氫箟涓涓鎵 Delegate Sub dl_ShowProgress(ByVal iValue As Integer)Public Sub ShowProgress(ByVal iValue As Integer)If ProgressBar1.IsDisposed Then Return End If If ProgressBar1.InvokeRequired = True Then Dim pInvoke As New dl_ShowProgress(AddressOf ...
  • vb.net 澶氱嚎绋璋冪敤鍙︿竴绐楀彛,鍋囨鐜拌薄,濡備綍瑙e喅
    绛旓細鎰熻闂鍑哄湪 Form2.Show() '鍚姩鍊掕鏃舵樉绀虹獥鍙 杩欎竴鍙ヤ笂銆傝繖涓鍙ュ簲璇ュ彧闇瑕佹墽琛屼竴娆″氨琛屼簡銆傛妸瀹冩斁鍦╰imer涓紝澶氭璋冪敤锛岄犳垚鍋囨銆
  • vb.net澶氱嚎绋闂
    绛旓細thread = New System.Threading.Thread(AddressOf DoStuff)thread.Start()Private Sub DoStuff() 'error occurs here' Me.Text = "Stuff"End Sub 鏂规1:Private Sub DoStuff() Me.CheckForIllegalCrossThreadCalls = False Me.Text = "Stuff"End Sub 鏂规浜宼hread = New System.Threadin...
  • 璋佽兘鍒嗕韩涓涓vb.net澶氱嚎绋鐨勭畝鍗曚緥瀛,璇佹槑绾跨▼涔嬮棿浜掍笉骞叉壈,鍔犱笂娉ㄩ噴鏈...
    绛旓細Imports SystemImports System.ThreadingPublic Class Form1 Dim TestThread1, TestThread2 As Thread Public Sub TestMethod1() Dim i As Integer i = 0 While (i < 1000) Label1.Text = i i += 1 End While End Sub Public Sub TestMethod2() Dim i A...
  • VB.net鍙互澶氱嚎绋鎺у埗鍚屼竴涓獥浣撳強鍏舵帶浠跺悧
    绛旓細涓嶅彲浠ワ紝浣嗘槸鑳藉鍦ㄤ富绾跨▼鐨勫熀纭涓婅皟鐢ㄥ鎵橈紙Invoke锛夈傦紙涓荤嚎绋嬩細琚崰鐢級渚嬪瓙锛欴im thr As Threading.Thread Public Delegate Sub VoidDelegate()Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load thr = New Threading.Thread(AddressOf Where)thr.Start()End Sub Pub...
  • VB.NET涓殑澶氱嚎绋鍜屽鎵樻槸浠涔堝叧绯? 鑳戒笉鑳界粰鎴戜竴涓氫織鏄撴噦鐨勮寖渚,璋...
    绛旓細arg)End Sub '濮旀墭鎸囧悜 Private Sub txtW1(ByVal txt As String)Me.RichTextBox1.AppendText(txt)End Sub /// 杩欐牱锛屼綘鍦澶氱嚎绋嬪簲鐢鏃讹紝鍦ㄥ叾浠栫嚎绋嬮噷鐢╰xtW(str)鏉ュ啓richtextbox锛屽氨涓嶄細浜х敓閿欒浜嗐備笉鐒讹紝鐩存帴鍨嚎绋嬪啓richtextbox锛屽彲鑳戒細鍑虹幇鍜孶I绾跨▼鐨勫啿绐併
  • vb.net澶氱嚎绋濡備綍杩斿洖鍙傛暟,涓句釜渚嬪瓙,璋㈣阿
    绛旓細Public Class Form1 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(Sq...
  • vb.net涓ゆ绋嬪簭澶氱嚎绋杩愯闂
    绛旓細绠鍗曞疄鐜扮殑璇濆彲浠ヨ瘯璇旴ackgroundWorker鎺т欢鏉ュ仛姣旇緝绠鍗曘
  • vb.net澶氱嚎绋,寰幆瀵艰嚧绐楀彛鐣岄潰鍋囨鐨勯棶棰
    绛旓細鍚屽銆傘備綘杩欓噷鐨勫啓娉曞叾瀹炴牴鏈病鏈夌敤鍒澶氱嚎绋 鍘熷洜寰堢畝鍗 浣犳槸瀹氫箟浜嗕竴涓猅鐨勬柊绾跨▼锛屼絾鏄緢鍙儨浣犲湪BeginDoSub杩欎釜鐙珛鐨勭嚎绋嬩腑鍙堝畾涔変簡涓涓猟eSomeSub鐨勫鎵橈紝骞朵笖鐩存帴鐢∕e.Invoke鎶婂疄闄呯殑鎵ц浠诲姟鎻愪氦缁欑晫闈富绾跨▼杩愯浜 鎵浠ヤ綘鐨勫浘鐗囩殑澶勭悊鍑芥暟瀹為檯涓婃槸鍦ㄤ富绾跨▼涓繍琛岀殑锛屾柊绾跨▼绛変簬娌$敤 姝g‘鐨勪綔娉...
  • 浣犲ソ,鏄彧鏈VB.NET鑳澶氱嚎绋,杩樻槸鎵鏈塚B閮借兘瀹炵幇澶氱嚎绋?
    绛旓細3銆佽繘涓姝ョ壒鍖栧埌VB涓婂幓璇淬俈B鍩轰簬VB鐨勮繍琛屽簱锛屽畠鐨勮繍琛屽簱鍙堝熀浜巜in鐨凙PI锛堬紙Application Programming Interface,搴旂敤绋嬪簭缂栫▼鎺ュ彛锛夋槸涓浜涢鍏堝畾涔夌殑鍑芥暟锛夛紝涔熷氨鏄锛孷B鐨勫緢澶氾紙澶氬埌90%浠ヤ笂锛夌殑鍔熻兘鏄洿鎺ュ熀浜庤皟鐢╳indows鎻愪緵鐨勪竴浜涘熀鏈帴鍙e嚱鏁般4銆VB.net鏈変粈涔堜笉鍚屽憿锛屽畠鍩轰簬.net杩愯搴撱備粈涔 鎰忔濓紵
  • 扩展阅读:.net多线程面试题 ... vbnet线程用法 ... 多线程应用 ... 多线程的一般应用场景 ... 英特尔cpu针脚对照表 ... 多线程下载器最新版本 ... 安卓多线程下载 ... 下载可调线程调多少好 ... c#异步多线程 ...

    本站交流只代表网友个人观点,与本站立场无关
    欢迎反馈与建议,请联系电邮
    2024© 车视网