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

问题描述 投票:0回答:3

所以我有一个方法,可以获取

Dictionary
List<myObj>
,然后循环遍历字典的键并将每个
List<myObj>
传递到单独的线程。

这是一些代码/伪代码:

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
}

问题在于,在执行

ProcessList
期间,
myList
参数只是发生了变化。

我在启动线程之前循环了列表,然后立即在线程内循环,我发现结果是不同的。

我已经通过将

Dictionary
变量设置为全局来解决了这个问题(我认为!)。使用
[ThreadStatic]
属性是可能的修复列表中的下一个。

我真正想知道的是,为什么当

myList
对象在
ProcessList()
中重新分配时,
myList
对象会在
ProcessEntries()
内发生变化?这不是两个不同的
Lists
吗?如果默认情况下所有参数传递都是按值传递,那么为什么
ProcessList()
函数没有
myList
的本地副本? (是吗?)

有没有办法指定要将参数传递给线程,并且在执行过程中不让父线程或其他线程更改它? (这类似于全局变量的

[ThreadSafe]
属性)

c# multithreading parameter-passing threadstatic
3个回答
2
投票

我怀疑您的伪代码实际上并不能准确反映您的真实代码。我怀疑你的real代码看起来像这样:

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 的博客文章了解更多信息。

如果这不是问题所在,请给出一个“真实”示例而不是伪代码。一个简短但完整的示例来演示问题将是理想的选择。


1
投票


0
投票
引用

,因此,如果您在某处对其进行修改,则各处都会有所不同。

© www.soinside.com 2019 - 2024. All rights reserved.