First, you should rethink your design regarding the large number of
threads. I cannot think of any reason whatsoever to have that many
threads...ever.
It sounds like your best option to communicate with the worker threads
is through a blocking queue. Basically, the worker threads will sit
idle in an infinite loop waiting for an object to appear in the
queue. Once the object is enqueued by the main thread the worker
thread will wake and dequeue for processing. After processing is
complete the worker thread will spin around to the beginning of the
loop again wait for the next object to appear.
Here is a simple example of creating something like a waitable queue.
Basically, the consumer thread waits on the global queues waithandle. This
gets set everytime an object is added to the queue. A threading timer acts as
a procducer thread, firing at different intervals and inserting random
commands. This is a very simple implmentation (one i worked up in a few
minutes time for another thread on the msdn forums), and to be honest probably
would fall down with multiple producers/consumers - but, it is a place to
start for the OP.
Option Strict On
Option Explicit On
Imports System.Collections.ObjectModel
Imports System.Collections.Generic
Imports System.Threading
Module Module1
Private wq As New WaitableQueue(Of String)
Private pt As New Threading.Timer(AddressOf Producer, Nothing, 5000, 500)
Private e As Boolean
Private commands() As String = {"command 1", "command 2", "command 3", "command 4"}
Private rnd As New Random()
Sub Main()
Dim ct As New Thread(AddressOf Consumer)
ct.Start()
Console.ReadKey()
e = True
End Sub
Sub Producer(ByVal state As Object)
Dim command As String = commands(rnd.Next(0, commands.Length))
Console.WriteLine("enqueuing {0}", command)
wq.Enqueue(command)
pt.Change(rnd.Next(0, 1000), rnd.Next(0, 1000))
End Sub
Sub Consumer()
While Not e
wq.SetEvent.WaitOne()
Dim command As String = wq.Dequeue()
Console.WriteLine("executing {0}", command)
End While
End Sub
Class WaitableQueue(Of T)
Implements IEnumerable(Of T), ICollection, IDisposable
Private _sync As New Object
Private _queue As New Queue(Of T)
Private _wait As New AutoResetEvent(False)
Public Sub Enqueue(ByVal item As T)
SyncLock _sync
_queue.Enqueue(item)
_wait.Set()
End SyncLock
End Sub
Public Function Dequeue() As T
SyncLock _sync
Return _queue.Dequeue()
End SyncLock
End Function
Public ReadOnly Property SetEvent() As WaitHandle
Get
Return _wait
End Get
End Property
Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of T) Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator
Return DirectCast(_queue, IEnumerable(Of T)).GetEnumerator()
End Function
Public Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
Return DirectCast(_queue, IEnumerable).GetEnumerator()
End Function
Public Sub CopyTo(ByVal array As System.Array, ByVal index As Integer) Implements System.Collections.ICollection.CopyTo
DirectCast(_queue, ICollection).CopyTo(array, index)
End Sub
Public ReadOnly Property Count() As Integer Implements System.Collections.ICollection.Count
Get
Return _queue.Count
End Get
End Property
Public ReadOnly Property IsSynchronized() As Boolean Implements System.Collections.ICollection.IsSynchronized
Get
Return DirectCast(_queue, ICollection).IsSynchronized
End Get
End Property
Public ReadOnly Property SyncRoot() As Object Implements System.Collections.ICollection.SyncRoot
Get
Return DirectCast(_queue, ICollection).SyncRoot
End Get
End Property
Private disposedValue As Boolean = False ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: free other state (managed objects).
_wait.Close()
End If
' TODO: free your own state (unmanaged objects).
' TODO: set large fields to null.
End If
Me.disposedValue = True
End Sub
#Region " IDisposable Support "
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
End Module