C#线程参数在线程执行期间发生变化 - 为什么?

时间:2010-08-05 16:48:03

标签: c# multithreading parameter-passing threadstatic

所以我有一个获取List of the Dictionary< myObj>的方法,然后遍历字典的键并传递每个List< myObj>到另一个线程。

以下是一些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);

        }    
    }
}

public static void ProcessList(List<myObj> myList) {

    // Process entries
    // read-only operations on myList

}

问题是在执行ProcessList期间,myList参数只会改变。

我在线程开始之前已遍历列表,然后立即在线程内部,我发现结果不同。

我已经通过使Dictionary变量全局解决了问题(我认为!)。使用[ThreadStatic]属性是可能修复列表的下一个。

我真正想知道的是为什么myList对象在ProcessList()内部发生变化,大概是在ProcessEntries()中重新分配myList对象的时候?这些不是两个不同的列表吗?如果默认情况下所有参数传递都是值,为什么ProcessList()函数没有myList的本地副本? (是吗?)

有没有办法指定您希望将参数传递给线程,而不是在执行期间由父线程或其他线程更改? (这类似于全局变量的[ThreadSafe]属性)

3 个答案:

答案 0 :(得分:2)

我怀疑你的伪代码实际上并不是你真实代码的准确反映。我怀疑你的真正的代码如下所示:

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

如果是这种情况,问题是正在捕获pair变量 - 所以当你的线程开始时,它可能指的是不同的键/值对。

修复它的方法是使代码更像伪代码:

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();
}

有关详细信息,请参阅Eric Lippert's blog post on this

如果这不是出错的地方,请提供真实的示例,而不是伪代码。 short but complete example demonstrating the problem是理想的。

答案 1 :(得分:1)

还要确保其他线程不会影响您尝试使用的线程。一定要使用锁和监视器...几周之前就有一些问题..

答案 2 :(得分:0)

在这种情况下,您按值传递引用,因此如果您在某处修改它,那么每个地方都会有所不同。