Click to See Complete Forum and Search --> : C# thread parameters - parameter changes


Dudeman3000
August 5th, 2010, 12:26 PM
I’ve posted this question on a couple forums. Any threading guru among us know the answer?

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 System.Threading.Thread(new System.Threading.ThreadStart(delegate() {
ProcessList(myList);
}
myThread.Start();
}

}

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 does not remain static – it changes.

I have looped through the list in ProcessEntries() before kicking off the thread, and then immediately inside the thread / ProcessList() method, and I've found the results to be different.

I have since solved the problem (I think!) by making the Dictionary variable global and retrieving the list within the ProcessList() function, but I find this not to be ideal. Using the [ThreadStatic] property is next on the list of possible fixes.

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

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)
Is there an important distinction between primitive type thread parameters and custom object thread parameters that I’m unaware of?

D_Drmmr
August 5th, 2010, 03:29 PM
What I really want to know is why does the myList object change inside ProcessList(), presumably when the myList object is re-assigned in ProcessEntries() ? Are these not two different Lists in memory? If all parameter passing is by value by default, why does the ProcessList() function not have a local copy of myList ?

List is a reference type, so it is not copied by value. The parameter myList in the thread function refers to a value in the dictionary. If that gets changed, you have a race condition.

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)

Create a copy explicitly. Otherwise, you will have to synchronize.

Is there an important distinction between primitive type thread parameters and custom object thread parameters that I’m unaware of?
There is a difference between value types and reference types. If you don't know that, you should be learning basic C#, not threading. Don't run before you know how to walk.

Dudeman3000
August 5th, 2010, 04:19 PM
Thanks D_Drmmr,

The dictionary, lists in the dictionary, and objects in the list are never modified during execution.

My code / pseudo code, I posted possibly was too simplified. The ProcessList() method actually looks like this.

public static void ProcessList(List<myObj> myList, byte myObjProp_Parameter)

Each object in the list should have myObj.objProperty == myObjProp_Parameter. Before firing off each thread, I check that this is true and it is. During thread execution however, not all objects in the list have myObj.objProperty == myObjProp_Parameter. I'm unclear at this point as to whether the list is changing or the parameter is changing during thread execution.

I realize that the List<myObj> property is a reference type parameter (or more accurately the reference is passed by value) and that the byte is a value type parameter. However, the list is not modified anywhere. The byte parameter is created within a loop - foreach(byte myParam in myByteList) - so I think each myParam byte references a distinct mem location, and is therefore never changed.

In summary, I have a List of objs and a byte. Before I pass these to the new thread, each object in the list has a property that equals the byte. Immediately after passing these parameters to the thread, I check if all objs in the list have the property in question == byte parameter, and they do not. I simply can not explain this behavior.

With regards to reference vs value types, I thought I might be missing something with regards to threading parameters.

Arjay
August 5th, 2010, 11:18 PM
As D_Drmmr has said, if your dictionary and lists aren't read-only then you need to synchronize. If the any of the threads are changing the dictionary or any of the lists, you need to synchronize the dictionary and the lists. Instead of synchronizing each list another option would be to create deep copies of the lists (including deep copies of each of the myObjs in the list.

If the Lists (and each myObjs) aren't copied and any of the myObjs within the Lists change while being operated on by the secondary thread (i.e. the primary thread changes one or more myObj), then each myObjs should be synchronized.

Dudeman3000
August 6th, 2010, 10:24 AM
Thanks Arjay,

The Dictionary and Lists are not read-only however they are not altered during the process.

I will try copying the lists. Unfortunately some of this structure is designed to minimize memory usage. However, if this does indeed work, I'm still not clear on how the parameters to my thread method seems to change when no edits are made to the dictionary or the lists.

Thanks again,
Mark

Arjay
August 6th, 2010, 11:07 AM
However, if this does indeed work, I'm still not clear on how the parameters to my thread method seems to change when no edits are made to the dictionary or the lists.Are the myObj items within the lists changing?

Dudeman3000
August 6th, 2010, 11:50 AM
No. There is one function call to populate the objs, lists, and dictionary, and after that none of these objects should change.

This is the declaration that populates the myRegionEntries parameter within a SiteID loop.

List<CacheLogRegionEntry> myRegionEntries = myCLREDictionary[DictionaryKey];

This is the call without threading - say Call #1.

ClearRegionEntries_SingleThread(myRegionEntries, SiteID);

This is the call with threading - Call #2.

Thread myThread = new System.Threading.Thread(new System.Threading.ThreadStart(delegate()
{ ClearRegionEntries_SingleThread(myRegionEntries, SiteID);
}));
myThread.Start();


Within ClearRegionEntries_SingleThread I loop through the entries to make sure that each RegionEntry has SiteID_Property = SiteID (parameter). This is true for Call #1 (no threading), but is not true for Call #2.

Arjay
August 6th, 2010, 01:55 PM
Clearly something is changing otherwise you wouldn't have an issue.

Folks sometimes miss things that are changing. For example, consider a case where a UI listbox is bound to a list of items and a user has the ability to change each item or add/remove and item.

Now say this list and the objects are accessed from a secondary thread so that the some work is done on the list (and maybe each list item is updated from the secondary thread).

Often the developer will synchronize access to the list and/or each item in the list on the secondary thread level, but forget to synchronize the other side where the main UI accesses the list and items.