4

The .NET ConcurrentDictionary is susceptible to a race condition that may cause unexpected data as explained at the bottom of this MSDN article. I'm assuming that there are several factors to take into account.

Q: How should I write code that is not vulnerable to that race condition that may cause data loss?

In my scenario I have an input stream that has an always increasing index (n++). My thought is that I could detect missing data if the race condition occurs and re-send it. On the other hand, there may be a better way to do this that I'm unaware of.

Community
  • 1
  • 1
makerofthings7
  • 60,103
  • 53
  • 215
  • 448

1 Answers1

8

There is a general pitfall with concurrent collections (not limited to .net) that people have to be aware of, which is that individual operations may be thread-safe, but sequences of operations are not atomic. What I mean by this is the following: assume this scenario, where I have a concurrent collection with a Check and an Add operation, both atomic.

What I want to do is check if a value exists and if not, add it. So I can write this:

if(!collection.Check(value)) 
{
    collection.Add(value);
}

Although both operations are atomic, the above sequence is not, as a thread may be interrupted between the check and the add by another thread, which leads to inconsistent results. Thus, the entire sequence should be made atomic by wrapping it in a lock statement for example.

lock(locker)
{
   if(!collection.Check(value)) 
   {
       collection.Add(value);
   }
}
Tudor
  • 61,523
  • 12
  • 102
  • 142
  • Doesn't the lock cause a huge performance hit? (vs SpinLock). Would it be better if it's possible to detect missing data and just retransmit it when the dataloss occurs? – makerofthings7 May 12 '12 at 16:52
  • @makerofthings7: Yes, it can be a performance problem in apps that require very high performance and alternative methods can be used, like a lock-less version or a spin lock, since the actual code protected is rather small. – Tudor May 12 '12 at 16:53
  • 3
    I think more optimal to use double checked locking. if(!collection.Check(value)) { lock(locker) { if(!collection.Check(value)) { collection.Add(value); } } } – gabba May 12 '12 at 16:56
  • @Gabba thanks for the tip on Double Checked Locking... I'm learning about it now. http://en.wikipedia.org/wiki/Double-checked_locking – makerofthings7 May 15 '12 at 22:33