Threads and Collection

  • Thread starter Thread starter Johan Karlsson
  • Start date Start date
J

Johan Karlsson

Hi!

First of all, I didn't find a Threading newsgroup that I would figure this
post to belong to, and its not languagespecific so I hope this is the right
group.

Anyhow, consider the following:

You have a collection called A that is inherited from collectionbase. You
implement the Add and Remove method something like this:

Public Sub Add (byref addItem as SomeObject)
SyncLock me
list.add( addItem )
End SyncLock
End Sub

(And remove kinda the same way).

Two questions:

1) If the Add failes, what happens with the lock. Do I need to wrap this in
a try finally block?
2) If another thread is enumerating this collection, what happens when the
lock kicks in?

My dream scenario:
* Not to do anything to the code that read and enumerates the collection.
Basicaly read the collection with a for each statement knowing that its
threadsafe due to the next point.
* Only to add the synclock in the enumerations Add and Remove (and perhaps
Clear is I'll allow that to happen).

Am I dreaming or is this going to work?

Thanks

/Johan
 
Johan Karlsson said:
First of all, I didn't find a Threading newsgroup that I would figure this
post to belong to, and its not languagespecific so I hope this is the right
group.

Yup, no problem.
Anyhow, consider the following:

You have a collection called A that is inherited from collectionbase. You
implement the Add and Remove method something like this:

Public Sub Add (byref addItem as SomeObject)
SyncLock me
list.add( addItem )
End SyncLock
End Sub

(And remove kinda the same way).

Two questions:

1) If the Add failes, what happens with the lock. Do I need to wrap this in
a try finally block?

No - SyncLock effectively does:

Monitor.Enter (xxx)
Try
....
Finally
Monitor.Exit (xxx)
End Try
2) If another thread is enumerating this collection, what happens when the
lock kicks in?

That depends on whether the other thread owns the lock. If it doesn't,
then the Add will occur and then enumeration will likely fail. You
should instead make sure that the enumerating thread holds the same
lock that you acquire for adding/removing. You should also look into
the ICollection.SyncRoot property and lock on that, rather than Me
My dream scenario:
* Not to do anything to the code that read and enumerates the collection.
Basicaly read the collection with a for each statement knowing that its
threadsafe due to the next point.
* Only to add the synclock in the enumerations Add and Remove (and perhaps
Clear is I'll allow that to happen).

Am I dreaming or is this going to work?

You're dreaming. Enumerating the collection essentially requires it to
stay unchanged during the reading, which means you need a lock of some
kind to stop it from being modified while you're enumerating it.

However, you could get away with a ReaderWriterLock which needs to be
used appropriately for *all* reads and writes, and which would allow
multiple readers but only a single writer.
 
Jon Skeet said:
Yup, no problem.


No - SyncLock effectively does:

Monitor.Enter (xxx)
Try
....
Finally
Monitor.Exit (xxx)
End Try


That depends on whether the other thread owns the lock. If it doesn't,
then the Add will occur and then enumeration will likely fail. You
should instead make sure that the enumerating thread holds the same
lock that you acquire for adding/removing. You should also look into
the ICollection.SyncRoot property and lock on that, rather than Me


You're dreaming. Enumerating the collection essentially requires it to
stay unchanged during the reading, which means you need a lock of some
kind to stop it from being modified while you're enumerating it.

However, you could get away with a ReaderWriterLock which needs to be
used appropriately for *all* reads and writes, and which would allow
multiple readers but only a single writer.

This is the way its done today, but the framework core of the project I'm
working on is growing and ready to be released internally to more
developers. I'm kinda scared that someone will think, locking, aah, what
the... and just ignore the read and write lock, which would mean that the
code could fail somewhere else...

I guess the readerWriterLock is the way I have to go here and not to release
the "core-code". :)

Thank you for a quick answer!

/Johan
 
Johan Karlsson said:
This is the way its done today, but the framework core of the project I'm
working on is growing and ready to be released internally to more
developers. I'm kinda scared that someone will think, locking, aah, what
the... and just ignore the read and write lock, which would mean that the
code could fail somewhere else...

Sure - sooner or later, you can't stop people from shooting themselves
in the foot.
I guess the readerWriterLock is the way I have to go here and not to release
the "core-code". :)

Yup - although you may wish to expose *which* ReaderWriterLock to use
as a property of your collection.
 
Yup - although you may wish to expose *which* ReaderWriterLock to use
as a property of your collection.

That is a very good idea. Today they are just named after collection but
with a "Lock" attached. Like 'm_groupsLock'.
Thanks again for your quick answers!

/Johan
 
Back
Top