title: Using locks on objects in a Dictionary gives KeyNotFoundException
body: <p>I have some code which processes a number of <code>response</code> objects from my database in parallel (using <code>AsParallel()</code>). Each <code>response</code> has many <code>components</code>. The <code>responses</code> may share the same components. I do some modifications to the <code>component</code> data and save it to the db, so I need to prevent multiple threads working on the same <code>component</code> object at the same time.</p>
  
  <p>I use locks to achieve this. I have a <code>ConcurrentDictionary&lt;int, object&gt;</code> to hold all the necessary lock objects. Like this:</p>
  
  <pre><code>private static ConcurrentDictionary&lt;int, object&gt; compLocks = new ConcurrentDictionary&lt;int, object&gt;(); 
  var compIds = db.components.Select(c =&gt; c.component_id).ToList();
  foreach (var compId in compIds)
  {
      compLocks[compId] = new object();
  }
  </code></pre>
  
  <p>Then later on I do this:</p>
  
  <pre><code>responses.AsParallel().ForAll(r =&gt;
  {
  
      ... do some time consuming stuff with web services ...
  
      // this is a *just in case* addition, 
      // in case a new component was added to 
      // the db since the dictionary was constructed
      // NOTE: it did not have any effect, and I'm no longer 
      // using it as @Henk pointed out it is not thread-safe.
      //if (compLocks[c.component_id] == null)
      //{
      //    compLocks[c.component_id] = new object();
      //}
  
      componentList.AsParallel().ForAll(c =&gt;
      {
          lock (compLocks[c.component_id])
          {
              ... do some processing, save the db records ...
          }
      });
  });
  </code></pre>
  
  <p>This seems to run perfectly fine but towards the end of program execution (it runs for several hours as there are lots of data) I get the following exception:</p>
  
  <blockquote>
    <p>Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
       at System.Collections.Concurrent.ConcurrentDictionary`2.get_Item(TKey key)</p>
  </blockquote>
  
  <p>I am sure that the <code>ConcurrentDictionary</code> is being populated with every possible <code>component</code> ID.</p>
  
  <p>I have 3 questions:</p>
  
  <ol>
  <li><strong>How is this exception even possible, and how do I fix it?</strong></li>
  <li><strong>Do I need a <code>ConcurrentDictionary</code> for this?</strong></li>
  <li><strong>Is my understanding of how locking works correct in this instance / is there a better way of doing this?</strong></li>
  </ol>
  
  <h2>Post-Answer Edit</h2>
  
  <p>To make it clear what the cause of all this was, it's that <code>.AsParallel()</code> doesn't enumerate the collection of <code>responses</code>. It's lazy-evaluated, meaning new <code>responses</code> (and therefore new <code>components</code>) can be added to the collection during run-time (from other processes). Enforcing a snap-shot with <code>.ToList()</code> before the <code>.AsParallel()</code> fixed the problem.</p>
  
  <p>My code for adding <code>component</code> IDs to <code>compLocks</code> during run-time didn't remedy this problem is because it is not thread safe.</p>