Passing value parameter to Task in c#

2019-02-26 01:15发布

问题:

I have an issue with passing a long by value to a Task.

I have a list of ID's where I loop through each one, assign to a local variable then pass as a parameter to a new Task. I do not wait for the task to complete before looping round and processing the next ID. I keep an array of Tasks but this is irrelevant.

loop
    long ID = list[index];
    task[index] = Task.Factory.StartNew(() => doWork(ID));
end loop

If the list contained for example 100 and 200. I would want the first task called with 100 then the second task called with 200. But it does not, doWork receives 200 for both tasks so there is an issue when the value is copied.

I can demonstrate with some simple console code

class Program
{
   static void Main(string[] args)
   {
      long num = 100;
      Task one = Task.Factory.StartNew(() => doWork(num));
      num = 200;

      Console.ReadKey();
   }

   public static void doWork(long val)
   {
      Console.WriteLine("Method called with {0}", val);
   }
 }

The above code will always display

Method called with 200

I modified the code to wait for the task status to switch from WaitingToRun

static void Main(string[] args)
{
   long num = 100;
   Task one = Task.Factory.StartNew(() => doWork(num));
   while(one.Status == TaskStatus.WaitingToRun)
   {}
   num = 200;

   Console.ReadKey();
}

This improves things but not 100% proof, after a few runs I got Method called with 200

Also tried the following

while (true)
{
    if (one.Status == TaskStatus.Running | one.IsCompleted == true)
    break;
}

but again got 200 displayed.

Any ideas how you can guarantee the value passed to the task without waiting for the task to complete?

Any help/ suggestions appreciated Ade

回答1:

Any ideas how you can guarantee the value passed to the task without waiting for the task to complete?

Sure - just create a separate variable which isn't modified anywhere else. You can use a new scope to make that clear:

long num = 100;
Task one;
{
    // Nothing can change copyOfNum!
    long copyOfNum = num;
    one = Task.Factory.StartNew(() => doWork(copyOfNum));
}

You can't change the C# compiler to capture "the value of the variable when delegate is created" rather than capturing the variable, but you can make sure the variable isn't changed afterwards, which accomplishes the same thing.



标签: c# task