Introduction
Do you occasionally need multithreaded timed-out operations? Let me say, this is a very basic implementation, but is the best solution for trying many different methods for completing your operation before you choose the best one, and it lets you start from a small basic (but so easy to get) multithreaded stuff that you can grow or change as much as you like since this class is released under GNU LGPL compatible license (means I don't care anything).
I will refer to the example of a DNS resolving operation (scanner), but it can be any multithreaded timed-out operation.
Question: what should "atomically" do our operation? Here is an example (DNS resolving example, it's easy to write the atomic job):
Private Function MyJob(IP as Object)As Object
Dim IPString as String = IP
Try
System.Net.Dns.Resolve(IPString)
Return IPString
Catch
Return "NotResolved"
End Try
End Function
Now I want this to be multithreaded and don't want to wait for the DNS for more than 3 sec per thread.
This is where the class comes in handy.
To use the class, simply create a MOP MultiThreadedTimedOutOperation
instance:
Dim WithEvents MOP as MultiThreadedTimedOutOperation
Initialize MOP
by giving a reference to our atomic job function, and optionally, the maximum number of threads and the timeout.
MOP = New MultiThreadedTimedOutOperation(AddressOf MyJob,40,3000)
I want to scan my entire subnet. Imagine that, we have our subnet prefix stored in LocalSNPrefix
(String
) as ("1.2.3."), so add the 254 jobs just like this:
Dim I as integer
For I = 1 to 254
MOP.QueueJob(LocalSNPrefix + I.ToString)
Next
Now I want to start my operation:
MOP.StartOperation
Now I can have implemented (not necessary) a function to catch performstepevent
(to use with the progress bar). Anyway, you need to know when the operation is finished and of course get the results.
Private Sub OnOpFinish()Handles MOP.OpFinished
Dim S as Stack = MOP.GetResults()
Dim I as Integer
For I = 1 to S.count
Dim Result as string = S.Pop
If Not Result.Equals("NotResolved")
MessageBox.Show("ResolvedIP :" + Result)
Next
End sub
That's it. Anyway I don't suggest this class be used in any "release version" without "strong implementation" stuff like late binding objects, and often there would be no need to make sure that an atomic operation has finished if it is placed into a separate thread as the class does. In fact, often you will already have a function that supports timing out by its own.
And if you think you can do better, don't wait.
Here's the code, copy and paste it directly into your VB.NET project or download the file from the zip file.
Public Class MultiThreadedTimedOutOperation
Public Delegate Function Job(ByVal InitState As Object) As Object
Public Event PerformStep()
Public Event OpFinished()
Private JobStart As Job
Private Results As New Stack
Private TS As New Queue
Private ActiveThreads As Integer
Private ReadOnly MaxThreads As Integer = 40
Private ReadOnly Waittime As Integer = 3000
Public Sub New(ByVal Method As Job, Optional ByVal maxthreads _
As Integer = 40, Optional ByVal Timeout As Integer = 3000)
Me.MaxThreads = maxthreads
Me.Waittime = Timeout
JobStart = Method
End Sub
Public Sub QueueJob(ByVal UserJobStartState As Object)
TS.Enqueue(UserJobStartState)
End Sub
Public Sub StartOperation()
Dim t As New Threading.Thread(AddressOf MainJob)
t.ApartmentState = Threading.ApartmentState.MTA
t.Start()
End Sub
Public Function GetResults() As Stack
Return Results
End Function
Private Sub MainJob()
While TS.Count > 0
If ActiveThreads < MaxThreads Then
Do1Job()
RaiseEvent PerformStep()
End If
System.Threading.Thread.Sleep(Waittime / MaxThreads)
End While
RaiseEvent OpFinished()
End Sub
Private Sub Do1Job()
Dim t As New Threading.Thread(AddressOf TimingOutJob)
t.Start()
End Sub
Private Sub TimingOutJob()
ActiveThreads += 1
Dim t As New Threading.Thread(AddressOf JobInvoke)
t.Start()
If Not t.Join(Waittime) Then t.Abort()
ActiveThreads -= 1
End Sub
Private Sub JobInvoke()
Dim ThisJob As String = TS.Dequeue
Dim Result As Object = JobStart.Invoke(ThisJob, Nothing, Nothing)
If Not Result Is Nothing Then Results.Push(Result)
End Sub
End Class
...picture was not for codeproject hihihi.
well my usual way is to release only classes wich can be used by you very easily and quickly.