Параметры потока C # меняются во время выполнения потока - почему? - PullRequest
2 голосов
/ 05 августа 2010

Итак, у меня есть метод, который получает словарь списка , затем циклически перебирает ключи словаря и передает каждый список в отдельный поток.

Вот код / ​​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 (), предположительно, когда объект myList переназначается в ProcessEntries ()Разве это не два разных списка?Если вся передача параметров по умолчанию выполняется по значению, почему функция ProcessList () не имеет локальной копии myList?(не так ли?)

Есть ли способ указать, что вы хотите передать параметр потоку, а не изменять его родительским потоком или другими потоками во время выполнения?(Это будет похоже на атрибут [ThreadSafe] для глобальных переменных)

Ответы [ 3 ]

2 голосов
/ 05 августа 2010

Я подозреваю, что ваш псевдокод на самом деле не является точным отражением вашего реального кода.Я подозреваю, что ваш реальный код выглядит следующим образом:

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

См. ЭрикВ блоге Липперта об этом для получения дополнительной информации.

Если это не так, пожалуйста, приведите реальный пример, а не псевдокод. короткий, но полный пример, демонстрирующий проблему , был бы идеальным.

1 голос
/ 06 августа 2010

Также убедитесь, что другие потоки не влияют на поток, который вы пытаетесь использовать. Обязательно используйте замки и мониторы ... У вас были проблемы с этим всего несколько недель назад ..

0 голосов
/ 05 августа 2010

В этом случае вы передаете ссылку по значению, поэтому, если вы ее где-то измените, она будет отличаться везде.

...