使用线程工具
你可以通过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字段,用来设置与该类相关的线程的名字,以便作调试用。
上一页 [1] [2] [3] [4] [5] [6] [7] 下一页