dercon said:
I'm developing a multi-threaded application which contains a global
collection.
The main thread adds objects to the global collection while the worker
threads (between 10-20) read (for each... next) from the global
collection. I'm getting an error when the worker threads try to read
from the collection while the main thread is either adding or removing
items on the global collection. On the main thread I've tried using a
synclock when adding or removing items from the global collection but
that does not seem to be helping. I remember back in college my prof
was talking about Semaphores, Mutex, and Monitors... is there any such
construct in vb.NET that i can use?
:\\derian
First off, you must realize that iteration using For Each, even if
collection is syncronized is not thread safe... Exactly for the reasons you
specify. If a collection is modified by another thread during the
iteration, it invalidates the enumerator and throws an exception. There is
no way around this really except
A. Lock the collection throught the iteration
' code to add
SyncLock globalCollection
globalCollection.Add(new mytype)
end synclock
' code to iterate.
SyncLock globalCollection
For Each item as mytype in globalCollection
' do stuff with item
next
end synclock
With the above you are required to make sure that you use the synclock when
ever you want to add, remove, or iterate items. This is pretty inefficient,
since it is going to cause all threads to wait while one thread iterates the
collection.
B. Catch the exception.
You may want to go with option b. Again, you will need to catch the
exception thrown when the enumerator becomes invalid - in that case it may
be more logical to not use for each. You may want to use the IEnumerator
interface directly. This is air code so, you will definately want play
around with it
Dim enumerator as IEnumerator = globalCollection.GetEnumerator()
dim o as myobjecttype
do while true
try
if enumeator.movenext()
o = directcast(enumerator.current, myobjecttype)
' do stuff with object...
else
exit do
end if
catch
enmerator = globablCollection.GetEnumerator()
end try
loop
As for mutex, etc. There is a mutex class, but mutex's are really designed
for process syncronization rather then thread sync. They are global kernal
objects. What you really want is a critical section - which is what the
monitor class in System.Threading provides. Of course you don't often have
to use it directly because SyncLock is really just a shortcut for using
System.Threading.Monitor
There is also the ManualResetEvent class and
the AutoResetEvent class, which can be used to wait for events to occur on
other threads. One interesting class you may want to look at is the
ReaderWriterLock class. It is sort of like the Monitor class, but is
optimized for use with Single writer, multiple reader scenarious... Anyway,
just some thoughts and ramblings...
HTH,
Tom Shelton