vb.net的多线程

Dim tUdpThread As Thread
Dim tBroadCast As Thread
Dim tBroadCastExit As Thread
Dim startUdpThread As ClassStartUdpThread = New ClassStartUdpThread()
tUdpThread = New Thread(AddressOf startUdpThread.StartUdpThread)
tUdpThread.IsBackground = True
tUdpThread.Start()


Dim broadCast As ClassBroadCast = New ClassBroadCast()
tBroadCast = New Thread(AddressOf broadCast.BroadCast)
tBroadCast.IsBackground = True
tBroadCast.Start()


Dim receive As Thread = New Thread(AddressOf ReceiveNews)
receive.IsBackground = True

receive.Start()

3. Visual Basic.NET中多线程编程的实现

  3.1 线程的创建与管理

  用来创建和维护线程的基类是System.Threading.Thread类。它能够创建并控制线程,设置其优先级并获取其状态。它拥有Start, Stop, Resume, Abort, Suspend和Join (wait for)等方法操纵线程,还可以通过如Sleep, IsAlive, IsBackground, Priority, ApartmentState和ThreadState等方法查询和设置线程状态。
最直接的创建线程的方法是创建一个新的线程类实例,并使用AddressOf语句为要运行的线程传递任务。

  以下代码将名为myTask的子过程作为单独的线程运行:

Dim Thread1 As New System.Threading.Thread(AddressOf myTask)
Thread1.Start

  类似的,使用Thread类的Sleep方法可以阻滞当前线程,使用Suspend方法可以挂起线程,使用Resume可以重新启动挂起的线程,使用Abort方法可以停止一个线程,使用Join方法可以使当前线程等待其它线程运行结束。

  3.2 线程取消

  多线程的一个优点是,应用程序的用户界面部分始终可以做出响应,即使其它线程正在执行任务。通过同步事件和作为标志的字段可以通知其它线程停止。要取消一个或多个正在运行的线程,可以调用 CancelTask() 方法。

  3.3 线程的优先级

  不同的线程具有不同的优先级,而优先级决定了线程能够得到多少CPU时间。高优先级的线程通常会比一般优先级的线程得到更多的CPU时间,如果程序中存在不止一个高优先级的线程,操作系统将在这些线程之间循环分配CPU时间。一旦低优先级的线程在执行时遇到了高优先级的线程,它将让出CPU给高优先级的线程。在Visual Basic.NET中,System.Threading.Thread.Priority枚举了线程的优先级别,这些级别包括Highest、AboveNormal、Normal、BelowNormal、Lowest。新创建的线程初始优先级为Normal。

  3.4 线程的状态

  线程从创建到终止,它一定处于某一个状态,而这个状态是由System.Threading.Thread.ThreadState属性定义的。当一个线程刚被创建时,它处在Unstarted状态,然后Thread类的Start() 方法将使线程状态变为Running状态,如果不调用相应的方法使线程挂起、阻塞、销毁或者终止,则线程将一直保持这样的状态。挂起的线程处于Suspended状态,直到我们调用resume()方法使其重新执行,这时候线程将重新变为Running状态。一旦线程被销毁或者终止,则线程处于Stopped状态,处于这个状态的线程将不复存在。线程还有一个Background状态,它表明线程运行在前台还是后台。而在一个确定的时间,线程可能处于多个状态。参见图2。


图2 线程状态转换

  3.5 线程池

  在应用程序中使用多线程操作能优化应用程序性能,但是多线程往往需要花费更多的代码和精力去控制线程以及实现线程之间的轮询和状态转换。使用线程池则可以自动完成这些工作,同时还可以优化计算机的访问性能,从而更加有效的利用多线程的优势。使用线程池,可以使用要运行的过程的委托来调用 ThreadPool.QueueUserWorkItem 方法,VB .NET 将创建线程并运行该过程。以下代码说明了如何使用线程池启动多个任务。

Sub DoMyWork()
Dim MyPool As System.Threading.ThreadPool ' 将一个任务排队
MyPool.QueueUserWorkItem(New System.Threading.WaitCallback(AddressOf Task1))
MyPool.QueueUserWorkItem(New System.Threading.WaitCallback(AddressOf Task2))
End Sub

  如果要启动很多单独的任务,但并不需要单独设置每个线程的属性,则线程池将非常有用。每个线程都以默认的堆栈大小和优先级启动。默认情况下,每个系统处理器上最多可以运行25个线程池线程。超过该限制的其它线程会被排队,直至其它线程运行结束后它们才能开始运行。
线程池并不是在所有的情况下都适用,当需要特定优先级的线程时就没法通过线程池来实现。

  3.6 线程的同步

  在多线程应用中,我们需要考虑不同线程之间的数据同步和防止死锁。当两个或多个线程之间同时等待对方释放资源的时候就会形成线程之间的死锁。为了防止死锁的发生,我们需要通过同步来实现线程安全。在Visual Basic.NET中提供了三种方法来完成线程的同步。

  (1) 代码域同步:使用Monitor类可以同步静态/实例化的方法的全部代码或者部分代码段。

  (2) 手工同步:可以使用不同的同步类(诸如WaitHandle, Mutex, ReaderWriterLock, ManualResetEvent, AutoResetEvent 和Interlocked等)创建自己的同步机制。这种同步方式要求你自己手动的为不同的域和方法同步,这种同步方式也可以用于进程间的同步和解除由于对共享资源的等待而造成的死锁。

  (3) 上下文同步:使用SynchronizationAttribute为ContextBoundObject对象创建简单的,自动的同步。这种同步方式仅用于实例化的方法和域的同步。所有在同一个上下文域的对象共享同一个锁。

  4. 结束语

  本文讨论了Visual Basic.NET中多线程开发技术。多线程技术是实现需要并发执行的应用程序的较好选择,尤其对于大部分时间被阻塞的程序段,例如在开发访问网络资源,系统开销比较大的操作或实现快速的用户界面响应时,具有不可替代的作用。但由于每个线程都需要额外的内存来创建,同时还需要处理器时间片来运行和管理线程,因此如果创建的线程过多,反而会降低应用程序的性能。所以在设计多线程应用程序时,应慎重对待,建立合理的系统模型,这样才能使应用程序获得最佳的性能。


开发者一直要求微软为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

Private _mutex As New Threading.Mutex

_mutex.WaitOne()

_mutex.ReleaseMutex()


VB.net使用多线程与委托解决时间延迟的问题 问题的来由:设置保存后,希望有提示“已保存”,并在提示出现后,延时5秒,随后提示自动消失就是下文中Label7.text的显示变成""最早是希望用thread.sleep 来解决的,最简单:Private Sub main() Label7.Text = "已保存" Threading.Thread.Sleep(5000) Label7.Text = "" End Sub 但是会造成页面无反应,假死5秒,相当不爽直接使用 DoEvents() ,也会假死:Private Sub main() 阅读详情

相关推荐

C# Task WaitAll和WaitAny

Task 有静态方法WaitAll和WaitAny,主要用于等待其他Task完成后做一些事情,先看看其实现部分吧: public class Task : IThreadPoolWorkItem, IAsyncResult, IDisposable { //Waits for all of the provided Task objects to complete execution.

dz45693的专栏 9209

如何使用vb.net多线程

可能一些小程序用不上,单线程就可以完成,但是很多程序往往需要多个线程同时操作,或者用辅助线程来完成主线程的工作,    多线程对于一个程序员来说是一个必须逾越的槛。最近在写一个程序,设备要同时登陆3台设备,如果使用单线程排队完成,时效性就达不到要求,应次没办法必须要学习多线程,那么如何使用vb.net多线程呢?下面是我百度搜索的一片多线程使用实例,先参考: 线程的基本操作 Dim Td As

编程之路 1万+

使用VB.NET开发多线程

   摘要:.NET 框架提供了新的类,可以方便地创建多线程应用程序。本文介绍如何使用 Visual Basic® .NET多线程编程技术来开发效率更高、响应速度更快的应用程序。 目录简介 多线程处理的优点 创建新线程 同步线程 线程计时器 取消任务 总结 简介过去,

wuhuwy的专栏 5999

VB.NET多线程技术及其实现【转载】

摘 要: Visaul Basic 在6.0之前的版本中对多线程并没有提供一个很好的支持,而微软的.NET框架提供了新的类库,从而可以方便地创建多线程应用程序。本文首先概述了进程、线程以及应用程序域的相互关系,随后介绍了如何使用Visual Basic.NET多线程编程技术来开发效率更高,响应速度更快的应用程序。   关键词 .NET框架 Visual Basic.NET 多线程 同步 ...

weixin_30482181的博客 622

VB.Net多线程及委托

VB.Net多线程及委托   一、多线程:在一个程序中,这些独立运行的程序片断叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。多线程处理一个常见的例子就是用户界面。利用线程,用户可按下一个按钮,然后程序会立即作出响应,而不是让用户等待程序完成了当前任务以后才开始响应。用多线程的目的就是提高应用程序对事务处理能力,当

Goldxwang的博客 7127

VB.NET多线程开发实例

VB.NET(Visual Basic.NET)是为适应Microsoft .NET框架的需要,对Visual Basic进行了重大改造后的开发工具。它比Visual Basic 6.0功能更强大,更易于使用。其中最重要的变化就是对象继承,在VB.NET中,所有可管理的类型都衍生自System.Object。作为编程工具,最重要的一个特性就是垃圾碎片的回收,它由CLR(Common Languag

★★创造未来★★ 1978

基于VB.NET多线程编程实现

基于VB.NET多线程编程实现  摘 要 Visaul Basic 在6.0之前的版本中对多线程并没有提供一个很好的支持,而微软的.NET框架提供了新的类库,从而可以方便地创建多线程应用程序。 本文首先概述了进程、线程以及应用程序域的相互关系,随后介绍了如何使用Visual Basic.NET多线程编程技术来开发效率更高,响应速度更快的应用程序。   关键词 .NET框架 Visual Bas

oakeil的专栏 872

VB.NET多线程应用

其中的一个问题是如何将程序的数据由线程类的构造器传入或者传出,也就是说,对于放到另外一个线程中的过程,你既不能传参数给它,也不能由它返回值。休眠和挂起的区别是,后者并不立刻让线程进入一个等待的状态,线程并不会挂起,直到.NET runtime认为现在已经是一个安全的地方来挂起它了,而休眠则会立刻让线程进入一个等待的状态。在许多的情况下,你需要建立一个新的线程来进行后台的处理,这样可提高应用的可用性,否则,一个长的处理就可以令程序的响应变得很慢,例如你按下表格上的一个取消按钮,却很久都没有响应。

chinaherolts2008的博客 2219

VB.NET 2010多线程编程教程

在当今的软件开发领域,多线程技术是提高应用程序性能和效率的重要手段。VB.NET作为一种成熟且功能强大的编程语言,其对多线程的支持也是强大的和灵活的。本章节旨在为读者提供VB.NET多线程技术的全面概览,帮助读者建立对VB.NET多线程应用的基础理解。多线程可以实现同时执行多个任务,对于需要处理大量计算或I/O密集型操作的应用程序来说,这是提升用户体验和系统响应速度的关键。VB.NET提供了一系列的工具和对象,比如线程、锁、同步事件以及线程池等,来帮助开发者有效地管理多线程

weixin_42510201的博客 1238

vb.net多线程例子

Public Class Form1    Inherits System.Windows.Forms.Form     Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click        Dim td1 As New System.Threading

Ben的专栏 985

vb.net中使用多线程

在对POS机上的销售系统进行了再次修改之后,又对这个系统进行充分而有详细的考虑。主要是对健壮性方面,要考虑到所有可能出现的问题。 昨天坤哥提出了一中出错的可能,就是如果说要进行打印的话没有纸了,或者是纸不够了怎么办? 按照我们这个程序的设计来说,这时候会程序会进入等待状态,这意味着现在无法进行任何操作,如果时间过于长的话,这时候可能会导致程序意外崩溃,虽然进过测试我们的程序不会崩溃,但是如果长时间的无法操作并且也没有提示的话那是一件十分不美好的事情。 因此,这是按照逻辑应该有一个提示

the_fire的技术博客 1万+

VB.net 多线程实例

VB.NET(Visual Basic.NET)是为适应Microsoft .NET框架的需要,对Visual Basic进行了重大改造后的开发工具。它比Visual Basic 6.0功能更强大,更易于使用。其中最重要的变化就是对象继承,在VB.NET中,所有可管理的类型都衍生自System.Object。作为编程工具,最重要的一个特性就是垃圾碎片的回收,它由CLR(Common Languag

EricBai的专栏 2228

[VB.NET]多线程——高级同步技术

多线程应用程序通常使用等待句柄和监视器对象来同步多个线程。下表介绍了可用于同步线程的部分 .NET 框架类。类 用途 AutoResetEvent  等待句柄,用于通知一个或多个等待线程发生了一个事件。AutoResetEvent 在等待线程被释放后自动将状态更改为已发出信号。  Interlocked  为多个线程共享的变量提供原子操作。 ManualResetEvent  等待句柄,用于通

VB.NET学习网-VB.NET实例、VB.NET教程、VB.NET源码下载 7632

关于VB.NET实现多线程拷贝文件

此示例结合了 `System.Threading` 命名空间的功能以及文件操作的相关 API。以上代码定义了一个名为 `CopyFile` 的方法用于单个文件的复制,并将其封装在一个独立的线程中运行。对于更加复杂的场景,还可以引入异步事件(如 `OnCompleted` 或自定义委托),从而进一步增强程序的灵活性和可扩展性。在此示例中,`BackgroundWorker` 被用来执行文件复制任务,同时允许 UI 线程保持响应状态。- **异步事件驱动模型**:更适合复杂业务逻辑下的解耦设计。

cncbook1979的博客 992

VB.NET多线程实例

前言 因为有一个项目要使用到多线程,以前对于多线程使用的较少,翻阅了书籍之后,就做了一个多线程的小例子。 对于多线程来讲,其实并没有想象中的那么复杂,只要了解其原理,然后再根据自己的业务需求合理使用就可以了。 vb.net多线程实例相关代码 Imports System.Threading '先引用 Dim thread1 As Thread '定义一个线程 thread1 = Ne...

贼冷的冰雨 989
上一篇: vb.net的委托调用
下一篇: vb.net的序列化
iteye_6236
博客等级 码龄8年 47粉丝 0原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值