Входной параметр потока

#c# #multithreading #visual-studio #thread-safety

#c# #многопоточность #visual-studio #безопасность потоков

Вопрос:

Я хочу запустить класс с другим значением в списке потоков. вот так :

      int index = 0;
     foreach (TreeNode nd in tvew.Nodes[0].Nodes)
     {
         threadping[index] = new Thread(delegate()
         { this.Invoke(new DelegateClientState(InvokeCheckNetworkState), new object[] {nd}); });

         threadping[index].Name = nd.Name;
         threadping[index].IsBackground = true;
         threadping[index].Start();

         index  ;
     }
  

но когда я отлаживаю код, я вижу, что параметр класса — это просто последнее значение.
я имею в виду, что когда я просматриваю класс thread, я вижу, что каждый раз, когда этот класс запускается, значение входного параметра является последним значением для последнего потока.

Кто-нибудь может сказать мне, ПОЧЕМУ?

Комментарии:

1. Можете ли вы показать код, в котором вы инициализировали коллекцию threadPing. И что такое «параметр класса» или какой класс потока вы отлаживаете?

Ответ №1:

Это потому, что переменная nd фиксируется в замыкании. При запуске потоков все они ссылаются на один и тот же экземпляр TreeNode, а именно на последний, которому был назначен nd . Для исправления используйте отдельную переменную, которая не изменяется в пределах области видимости:

  foreach (TreeNode nd in tvew.Nodes[0].Nodes)
 {
     var current = nd;
     threadping[index] = new Thread(delegate()
     { this.Invoke(new DelegateClientState(InvokeCheckNetworkState), new object[] {current}); });
  

Если мы получаем compiler-technical, это происходит потому, что компилятор генерирует анонимный класс, содержащий вашу переменную цикла, чтобы сделать его доступным для делегата потока. Это ожидаемое поведение, хотя, возможно, немного нелогичное, когда вы сталкиваетесь с ним в первый раз.

Для более подробного объяснения замыканий и захвата переменных, смотрите раздел «Захваченные переменные» здесь (нижняя часть) в статье Джона Скита или в этой статье Эрика Липперта. Это обычно известно как ошибка «доступ к измененному закрытию». Если вы выполните поиск по термину в StackOverflow или Google, вы получите множество обращений, объясняющих это.

Комментарии:

1. спасибо, это работает. другой вопрос: почему мои потоки не работают одновременно? я указываю точку останова в первой строке «InvokeCheckNetworkState», которая возникает при завершении первого цикла. это похоже на то, что потоки ожидают завершения предыдущего потока. я имею в виду, что ты не работаешь одновременно. Что мне делать?