Run multiply instances of the same method simultan

2019-06-07 23:08发布

问题:

I really don't understand Tasks and Threads well. I have a method inside three levels of nested for that I want to run multiple times in different threads/tasks, but the variables I pass to the method go crazy, let me explain with some code:

List<int> numbers=new List<int>();
for(int a=0;a<=70;a++)
{
  for(int b=0;b<=6;b++)
  {
    for(int c=0;b<=10;c++)
    {
        Task.Factory.StartNew(()=>MyMethod(numbers,a,b,c));
    }
  }
}
private static bool MyMethod(List<int> nums,int a,int b,int c)
{
    //Really a lot of stuff here
}

This is the nest, myMethod really does a lot of things, like calculating the factorial of some numbers, writing into different documents and matching responses with a list of combinations and calling other little methods, it has also some return value (booleans), but I don't care about them at the moment. The problem is that no task reach an end, it's like everytime the nest call the method it refreshes itself, removing previous instances. It also give an error, "try to divide for 0", with values OVER the ones delimited by FORs, for example a=71, b=7, c=11 and all variables empty(that's why divided by zero). I really don't know how to solve it.

回答1:

The problem is, that you are using a variable that has been or will be modifed outside your closure/lambda. You should get a warning, saying "Access to modified closure".

You can fix it by putting your loop variables into locals first and use those:

namespace ConsoleApplication9
{
  using System.Collections.Generic;
  using System.Threading.Tasks;

  class Program
  {
    static void Main()
    {
      var numbers = new List<int>();

      for(int a=0;a<=70;a++)
      {
        for(int b=0;b<=6;b++)
        {
          for(int c=0;c<=10;c++)
          {
            var unmodifiedA = a;
            var unmodifiedB = b;
            var unmodifiedC = c;

            Task.Factory.StartNew(() => MyMethod(numbers, unmodifiedA, unmodifiedB, unmodifiedC));
          }
        }
      }
    }

    private static void MyMethod(List<int> nums, int a, int b, int c)
    {
      //Really a lot of stuffs here
    }
  }
}


回答2:

Check your for statements. b and c are never incremented.

You then have a closure over the loop variables which is likely to be the cause of other problems.

Captured variable in a loop in C#

Why is it bad to use an iteration variable in a lambda expression