69

What is the standard nowadays when one needs a thread safe collection (e.g. Set). Do I synchronize it myself, or is there an inherently thread safe collection?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
ripper234
  • 222,824
  • 274
  • 634
  • 905
  • 7
    Safe for which operations? – John Saunders Jun 05 '10 at 12:18
  • 2
    @John, you know, adding, reading etc... something like an java's concurrent collections. – ripper234 Jun 05 '10 at 20:50
  • 2
    you should update your question with this information. It makes a big difference that you want collections that are thread safe for everything, vs. a collection that is, for instance, thread safe for insert only. – John Saunders Jun 05 '10 at 23:38
  • 1
    @John - how does that change the answer? – ripper234 Jun 06 '10 at 22:22
  • 2
    if the answer is the .NET 4.0 collections, then it doesn't. But, in general, different collections can have different thread-safety and parallelism characteristics. For instance, a particular queue might be safe for multiple readers but only one writer. – John Saunders Jun 06 '10 at 23:18

4 Answers4

109

The .NET 4.0 Framework introduces several thread-safe collections in the System.Collections.Concurrent Namespace:

ConcurrentBag<T>
      Represents a thread-safe, unordered collection of objects.

ConcurrentDictionary<TKey, TValue>
    Represents a thread-safe collection of key-value pairs that can be accessed by multiple threads concurrently.

ConcurrentQueue<T>
    Represents a thread-safe first in-first out (FIFO) collection.

ConcurrentStack<T>
    Represents a thread-safe last in-first out (LIFO) collection.


Other collections in the .NET Framework are not thread-safe by default and need to be locked for each operation:

lock (mySet)
{
    mySet.Add("Hello World");
}
dtb
  • 213,145
  • 36
  • 401
  • 431
19

Pre .net 4.0 most collections in .Net are not thread safe. You'll have to do some work yourself to handle the synchronization: http://msdn.microsoft.com/en-us/library/573ths2x.aspx

Quote from article:

Collections classes can be made thread safe using any of the following methods:

Create a thread-safe wrapper using the Synchronized method, and access the collection exclusively through that wrapper.

If the class does not have a Synchronized method, derive from the class and implement a Synchronized method using the SyncRoot property.

Use a locking mechanism, such as the lock statement in C# (SyncLock in Visual Basic), on the SyncRoot property when accessing the collection.

Sync Root Property
Lock Statement

Object thisLock = new Object();
......
lock (thisLock)
{
    // Critical code section
}

In .net 4.0 the introduced the System.Collections.Concurrent namespace

Blocking Collection
Concurrent Bag
Concurrent Queue
Concurrent Dictionary
Ordable Partitioner
Partitioner
Partitioner T

kemiller2002
  • 113,795
  • 27
  • 197
  • 251
  • 4
    The object you are locking on should be an instance variable, otherwise it doesn't make sense because you are always locking on a new reference. – Femaref Jun 05 '10 at 13:21
  • 2
    That is true. This is just an example that was on the MSDN page on how the Lock code is used. – kemiller2002 Jun 05 '10 at 13:45
4

.NET 4 provides a set of thread-safe collections under System.Collections.Concurrent

treehouse
  • 2,521
  • 1
  • 21
  • 39
1

In a addition to the very useful classes in System.Collections.Concurrent, one standard technique in mostly-read-rarely-change scenarios (or if there are however frequent, but non-concurrent writes) that is also applicable to .Net is called Copy-on-write.

It has a couple of properties that are desirable in highly-concurrent programs:

  • collection object instances themselves are immutable (i.e. thread-safe, can be safely enumerated without locking)
  • modification can take as much time as it wants, performance and concurrency of reads are not affected
  • can be implemented generically to turn any data structure that is not thread-safe into one that is

Limitation: If there are concurrent writes, modifications may have to be retried, so the more concurrent writes get, the less efficient it becomes. (That's optimistic concurrency at work)

Edit Scott Chamberlain's comment reminded me that there's another limitation: If your data structures are huge, and modifications occur often, a copy-all-on-write might be prohibitive both in terms of memory consumption and the CPU cost of copying involved.

Community
  • 1
  • 1
Evgeniy Berezovsky
  • 18,571
  • 13
  • 82
  • 156
  • Microsoft provides a set of copy-on-write collections via NuGet via [Microsoft.Bcl.Immutable](https://www.nuget.org/packages/Microsoft.Bcl.Immutable), you can find more info [here](http://blogs.msdn.com/b/bclteam/archive/2012/12/18/preview-of-immutable-collections-released-on-nuget.aspx) – Scott Chamberlain Jun 11 '15 at 23:42
  • @ScottChamberlain Theirs are way more sophisticated than my simple, but generic, "copy all on write" approach, in that they copy only part of the data. So they are usable even changing huge data structures, which will be inefficient with copy-all-on-write, both in terms of the CPU cost of copying, and the memory consumption for holding multiple full copies in memory. – Evgeniy Berezovsky Jun 12 '15 at 00:09