Thread Parameters change during thread execution - why?

2.3k Views Asked by At

So I have a method that gets a Dictionary of List<myObj>, then cycles through the keys of the dictionary and passes each List<myObj> to a separate thread.

Here is some Code / Psuedo-Code:

public static void ProcessEntries()
{
    Dictionary<string, List<myObj>> myDictionary = GetDictionary();

    foreach(string key in myDictionary.keys)
    {
        List<myObj> myList = myDictionary[key];

        Thread myThread = new Thread(new ThreadStart(delegate()
        {
            ProcessList(myList);
        }    
    }
}

public static void ProcessList(List<myObj> myList)
{
    // Process entries
    // read-only operations on myList
}

The problem is that during execution of ProcessList the myList parameter simply changes.

I have looped through the list before kicking of the thread, and then immediately inside the thread, and I've found the results to be different.

I have since solved the problem (I think!) by making the Dictionary variable global. Using the [ThreadStatic] property is next on the list of possible fixes.

What I really want to know is why does the myList object changes inside ProcessList() presumably when the myList object is re-assigned in ProcessEntries()? Are these not two different Lists? If all parameter passing is by value by default, why does the ProcessList() function not have a local copy of myList? (does it?)

Is there a way to specify that you want to pass a parameter to a thread and not have it be altered by the parent thread or other threads during execution? (This would be similar to the [ThreadSafe] attribute for global variables)

3

There are 3 best solutions below

0
On

Also be sure that other threads don't affect the thread you're trying to use. be sure to use locks and monitors... Had some issues with that just few weeks ago..

0
On

You are passing a reference by value in that case, so if you modify it somewhere it will be different everywhwere.

0
On

I suspect your pseudo-code isn't actually an accurate reflection of your real code. I suspect your real code looks like this:

foreach(var pair in myDictionary)
{
    Thread myThread = new Thread(delegate() {
        ProcessList(pair.Value);
    });
    myThread.Start();
}

If that's the case, the problem is that the pair variable is being captured - so by the time your thread starts, it may be referring to a different key/value pair.

The way to fix it is to make the code precisely more like your pseudo-code:

foreach(var pair in myDictionary)
{
    // You'll get a new list variable on each iteration
    var list = pair.Value;
    Thread myThread = new Thread(delegate() {
        ProcessList(list);
    });
    myThread.Start();
}

See Eric Lippert's blog post on this for more information.

If this isn't what's going wrong, please give a real example rather than pseudo-code. A short but complete example demonstrating the problem would be ideal.