科技行者

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

知识库

知识库 安全导航

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

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

  • 扫一扫
    分享文章到微信

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

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

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

关键字:

  • 评论
  • 分享微博
  • 分享邮件
使用线程工具

  你可以通过Thread类来创建和管理自己的线程,System.Threading命名空间还提供了一个简单的方式来使用线程,这些线程由CLR分配的一个池得到。这样做是可能的,因为CLR自动在每个进程创建和管理一个线程池,这样做是为了用来处理异步的操作,例如I/O和事件。在池中,一个线程被分配Highest优先权利,它是用来监视队列中其它线程的状态的。使用ThreadPool类,你的代码可接进这个池,并且可以更有效地使用这个在运行时已经配置的体系。实际上,ThreadPool类可允许你提交工作项目(例如要执行的方法)到池中,它们会被随后的工作线程执行。

  如前所述,只有在应用需要的时候才使用线程,并且要经过仔细的分析。例如,使用线程池的一个很好的情形是,一个用来监听由一个或者多个信息队列中进入的新信息的Windows服务应用。虽然System.Messaging命名空间支持异步的操作,但是创建一个线程池可允许你控制一些特别的方面,例如有多少线程在处理信息和线程的生存时间。

  下面例子是一个经过简化的类,它使用ThreadPool类,用来监听一个MSMQ队列。

  列表11.9 QueueListener类,该类使用ThreadPool类来监听一个MSMQ队列

Option Strict Off

Imports System
Imports System.Threading
Imports System.Messaging
Imports Microsoft.VisualBasic

Public Class QueueListener
' Used to listen for MSMQ messages

 Protected Class EventState
 ' Used to store the event and any other state data required by the listener
  Public ResetEvent As ManualResetEvent
  Public ThreadName As String

  Public Overloads Sub New(ByVal myEvent As ManualResetEvent)
   MyBase.New()
   ResetEvent = myEvent
  End Sub
  
  Public Overloads Sub New(ByVal myEvent As ManualResetEvent, ByVal Name As String)
   MyBase.New()
   ResetEvent = myEvent
   ThreadName = Name
  End Sub
End Class


Private mstrMachine As String
Private mstrQueue As String
Private mWorkItems As Integer = 7
Private mFinished As Boolean = False
Dim mEvs() As ManualResetEvent

Public Property WorkItems() As Integer
Get
 Return mWorkItems
End Get
Set(ByVal Value As Integer)
 If Value > 15 Then
  mWorkItems = 15
 Else
  mWorkItems = Value
 End If
End Set
End Property

Public Sub New(ByVal Machine As String, ByVal Queue As String)
' Constructor accepts the necessary queue information
 mstrMachine = Machine
 mstrQueue = Queue
End Sub

Public Sub Listen(ByVal state As Object)
 ' Method that each thread uses to listen for messages

 ' Create a MessageQueue object
 Dim objMQ As System.Messaging.MessageQueue = New System.Messaging.MessageQueue()
 ' Create a Message object
 Dim objMsg As System.Messaging.Message ' = New System.Messaging.Message()
 ' Event from the state
 Dim evs As ManualResetEvent

 ' Cast the state into the event
 evs = state.ResetEvent

 ' Set the priority and name
 Thread.CurrentThread.Priority = ThreadPriority.BelowNormal
 Try
  If Not state.ThreadName Is Nothing Then
   Thread.CurrentThread.Name = state.ThreadName
  End If
 Catch e As Exception
  ' Thread name can only be set once
  ' Don't set it and get out
 End Try

 'Console.WriteLine("Listen {0} ", state.ThreadName)
 Try
 ' Set the path property on the MessageQueue object, assume private in this  case
  objMQ.Path = mstrMachine & "\private$\" & mstrQueue
  ' Repeat until Interrupt received
  While True
  Try
   ' Sleep in order to catch the interrupt if it has been thrown
   Thread.CurrentThread.Sleep(100)

   ' Set the Message object equal to the result from the receive function
   ' Will block for 1 second if a message is not received
   objMsg = objMQ.Receive(New TimeSpan(0, 0, 0, 1))

   ' Message found so signal the event to say we're working
   evs.Reset()
   ' Processing the message
   ProcessMsg(objMsg)
   ' Done processing

  Catch e As ThreadInterruptedException
   ' Catch the ThreadInterrupt from the main thread and exit
   Exit While
  Catch excp As MessageQueueException
   ' Catch any exceptions thrown in receive
   ' Probable timeout
  Finally
   ' Console.WriteLine("Setting Event " &    Thread.CurrentThread.GetHashCode())
   ' Done with this iteration of the loop so set the event
   evs.Set()
  End Try

  ' If finished then exit thread
  If mFinished Then
   'console.WriteLine("exiting " & thread.CurrentThread.GetHashCode)
   Exit While
  End If

 End While

 Catch e As ThreadInterruptedException
  ' Catch the ThreadInterrupt from the main thread and exit
 End Try

End Sub

 Private Sub ProcessMsg(ByVal pMsg As Message)
  ' Here is where we would process the message
 End Sub

 Public Sub Monitor()
  Dim intItem As Integer
  Dim objState As EventState

  ReDim mEvs(mWorkItems)
  mFinished = False

  'Console.WriteLine("Queuing {0} items to Thread Pool", mWorkItems)

  For intItem = 0 To mWorkItems - 1
   'Console.WriteLine("Queue to Thread Pool {0}", intItem)
   mEvs(intItem) = New ManualResetEvent(False)
   objState = New EventState(mEvs(intItem), "Worker " & intItem)
   ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf Me.Listen), _ objState)
  Next

 End Sub

 Public Sub Finish(Optional ByVal pTimeout As Integer = 0)
  'Console.WriteLine("Waiting for Thread Pool to drain")
  ' Make sure everyone gets through the last iteration
  mFinished = True
  ' Block until all have been set
  If pTimeout = 0 Then
   WaitHandle.WaitAll(mEvs) ' Waiting until all threads signal that they are done.
  Else
   WaitHandle.WaitAll(mEvs, pTimeout, True)
  End If
   'Console.WriteLine("Thread Pool has been drained (Event fired)")
  End Sub

End Class

  要注意该列表包含有两个类:EventState,它是一个protected的子类,还有QueueListener。EventState包含有一个称为ResetEvent的字段,它的类型是ManualResetEvent,用来确保所有的工作线程可以无中断地完成它的工作,这是通过使用ResetEvent字段得到其状态。该类还包含有一个ThreadName字段,用来设置与该类相关的线程的名字,以便作调试用。
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

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

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