views:

68

answers:

3

I have a collection of objects that's constantly changing, and I want to display some information about the contents every so often (my application is multi-threaded, and differently threads are constantly submitting requests to modify an object in the collection, so it's unpredictable).

If I lock the collection, I can iterate over it and get my information without any problems - however, this causes problems with the other threads, since they could have submitted multiple requests to modify the collection in the meantime, and will be stalled. I've thought of a couple ways around this, and I'm looking for any advice.

  • Make a copy of the collection and iterate over it, allowing the original to continue updating in the background. The collection can get large, so this isn't ideal, but it's safe.
  • Iterate over it using a For...Next loop, and catch an IndexOutOfBounds exception if an item is removed from the collection while we're iterating. This may occasionally cause duplicates to appear in my snapshot, so it's not ideal either.

Any other ideas? I'm only concerned about a moment-in-time snapshot, so I'm not concerned about reflecting changes in my application - my main concern is that the collection be able to be updated with minimal latency, and that updates never be lost.

+2  A: 

You might want to look into using some concurrent collections from System.Concurrent namespace, if you are using .NET Framework 4. For example iterators returned from the ConcurrentQueue<T> class represent a moment-in-time view of the collection and are not affected by change in the collection. Normal collection iterators will be invalidated by changes in the underlying collection. Otherwise, you have no choice, but to lock the collection first. Maybe there are third-party implementations of concurrent collections. But I have not looked into those. Here is information on thread-safe collections in .NET Framework 4.

http://msdn.microsoft.com/en-us/library/dd997305(v=VS.100).aspx

Strelok
I didn't realize these new types of Collections existed - ConcurrentBag(Of T) might be just what I'm looking for. Thanks for the link.
rwmnau
+1  A: 

I tend to use your first option, making an array with .ToArray() and iterating over that. Have you profiled it to see how slow it is making a copy? It's usually been negligible for me, even for large collections.

Adam Ruth
I've not timed the copy operation to see if it would be a bottleneck, but I figured it would since I only need a couple of properties from each object, but the objects can be complicated and multi-layered (they contain collections themselves). I'll do some testing, though, and see if .ToArray is quick enough to solve my problem.
rwmnau
I also have used toarray in multithread environment, because you can make a quick copy with lock, and your iteration operation over array will not blcok all other threads.
Akash Kava
It sounds like you don't need a deep copy, so the ToArray should be very quick for you since it only makes copies of the object references.
Adam Ruth
A: 

Making a copy of the collection typically requires you to lock the collection first, so no gain here compared with just locking it and iterating over it - unless your collection supports some sort of fast cloning.

I think an alternative can be to use different kinds of collections, ones that have better support for concurrent accesses, or an ability to return snapshots quickly. Another answer here linked to .net specific ones; if you're interested in implementing one yourself I would suggest this paper:

http://www.cs.tau.ac.il/~shanir/concurrent-data-structures.pdf

Oak
Depending on what you're doing while iterating it can be a big gain to first make a copy and then iterate. If the operation on each item in the collection takes some time, you'll have a shorter lock.
Adam Ruth