科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件用Visual Basic.Net创建多线程应用程序

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

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

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

作者:QQ新人类 来源:YESKY 2007年11月10日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
对资源的同步访问

  一般来说,你希望在独立的线程中运行各种处理,而不需要访问共享的资源。建议的方法如下:

  1、封装要运行的处理到一个类中,并且留一个入口来启动该处理,例如Public Sub Start()并且初始化变量来处理状态

  2、创建一个独立的类实例

  3、设置处理需要的实例变量

  4、在一个独立的线程中调用入口

  5、不要引用该类的实例变量

  只要使用这个方法,全部的实例变量对于线程都是“私有的”,因此可以无需担心同步的问题。

  不过,有时这种情况是不能避免的,例如数据库连接或者文件处理。为了确保某线程在访问这些资源时其它线程处于等待状态,你可以使用Monitor类和它的相关方法,包括有Enter, Exit, TryEnter, Wait, Pulse和PulseAll。

  例如,假定上面代码中的Instructors类包含了一个类级的SqlConnection对象,该对象被所有的方法共享,并且用来连接数据库。这就是一个资源共享的例子,它被类中的所有方法所共享。

  注意:

  虽然使用连接池可提供一个更富扩展性的方案,不过这个例子满足我们当前的需要,它让所有的数据库访问通过一个单一的数据库连接进行。这种方式对于需要一个持久的数据库连接的应用是适合的,不过不适合用在分布式的应用。

  这个例子中,我们假设在调用GetPhotos后,客户端继续调用一个使用该连接对象的方法。由于连接可能正在被GetPhotos使用,如果SqlConnection正在忙于处理其它的结果,该方法将会抛出一个例外。

  要避免这种情形,GetPhotos方法可以使用Monitor的共享方法在其代码中创建critical section。简单说来,critical section就是调用Monitor类的Enter和Exit方法所构成的代码块,通过它,访问的同步是基于传送至Enter方法的对象。也就是说,如果GetPhotos方法要独立地使用SqlConnection,它必须要创建一个critical section,在该section的开始部分,通过传送SqlConnection到Monitor的Enter方法中,并且在结束的时候调用Exit方法。被传送的对象可以是任何继承System.Object的对象。

  如果该对象正在被其它的线程使用,Enter方法将会阻塞直到对象被释放。你也可以调用TryEnter方法,该方法不会阻塞,它只会返回一个布尔值指示该对象是否在使用中。一旦进入critical section,GetPhotos方法可以使用SqlConnection执行一个存储过程,并且将结果写出来。在关闭结果集SqlDataReader后,就会调用Monitor类的Pulse方法,以通知等待队列中的下个线程该对象已经释放了。然后就会将线程移动到ready队列中,以便准备开始处理。PulseAll方法则通知全部的等待线程该对象准备被释放。最后就会调用Exit,从而释放monitor并且结束critical section部分。这部分代码的框架见下。

  同步的资源。以下的例子展示了GetPhotos方法将使用Monitor类来确保两个线程不会同时使用SqlConnection对象

Public Sub GetPhotos()

Dim cmSQL As SqlCommand
Dim sdrIns As SqlDataReader

Try
' Execute proc
cmSQL = New SqlCommand("usp_GetPhotos", mcnSQL)
cmSQL.CommandType = CommandType.StoredProcedure

' Enter critical section
Monitor.Enter(mcnSQL)
' Alternate code
' Do While Not Monitor.TryEnter(mcnSQL)
' Thread.CurrentThread.Sleep(100)
' Loop
sdrIns = cmSQL.ExecuteReader()
Catch e As Exception
End Try

Do While sdrIns.Read
' Read the data and write it to a binary stream
Loop

sdrIns.Close
Monitor.Pulse(mcnSQL)
Monitor.Exit(mcnSQL)
' Exited critical section

Return
End Sub

  很明显,critical sections仅应该在需要的时候创建,因为它们会阻塞线程,从而会影响整体的吞吐量。

  要同步线程间共享的实例变量,有一个很简单的技巧,这就是使用Interlocket类。该类包含有共享的Increment和Decrement方法,可以将修改变量和检查结果的操作结合成一个单一的操作。这样做是必需的,因为一个线程可以修改变量的值,在接着检查结果之前,它的运行时间就结束了。在该线程再次运行时,变量的值就有可能被其它的线程修改了。

  例如下面的代码增加Instructors类的mPhotosProcessed实例级变量的值:

Interlocked.Increment(mPhotosProcessed)

  Interlocked类还支持Exchange和CompareExchange的方法,它们的作用分别是设置变量为特定的值,或者在该变量等于某个值时才这样做。
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章