OdeToCode IC Logo

What's Wrong With This Code (#10)

Tuesday, January 9, 2007

This time, Joe Developer thinks he found a bug in the .NET framework. Joe read that the volatile modifier is "usually used for a field that is accessed by multiple threads without using the lock Statement". Joe wants to try this out, and writes the following class.

class Worker
{
    
public void Start()
    {
        queue =
new Queue<string>();

        
Thread[] threads = new Thread[maxThreads];
        
for (int i = 0; i < threads.Length; i++)
            threads[i] =
new Thread(PopulateQueue);

        
Array.ForEach(threads, delegate(Thread t) { t.Start(); });
        
Array.ForEach(threads, delegate(Thread t) { t.Join(); });
        
        
Debug.Assert(queue.Count == maxThreads * maxIterations);
    }

    
void PopulateQueue()
    {
        
for (int i = 0; i < maxIterations; i++)
        {
            queue.Enqueue(
"foo");
        }
    }

    
volatile Queue<string> queue;

    
const int maxThreads = 5;
    
const int maxIterations = 1000000;
}

This code ran successfully at least a dozen times, then suddenly blew up with the following exception:

System.ArgumentException was unhandled
Message="Destination array was not long enough.
Check destIndex and length, and the array's lower bounds."
Source="mscorlib"
ParamName=""
StackTrace:
at System.Array.Copy ...
at System.Collections.Generic.Queue`1.SetCapacity ...
at System.Collections.Generic.Queue`1.Enqueue ...
at Worker.PopulateQueue ...
...

Joe thinks something has gone terribly wrong in the CLR, and for once, Joe would like to show his boss a problem in someone else's software. What should his boss think?