0

Very new to async programming and trying to test some things. Any clue what I need to do to ensure that my Debug.WriteLine() statements will print the "correct" value for "i" (from my original loop)? The below attempt (of assigning to x and passing that value down to my async method) didnt work (as i never get a 0 value and then usually get the last value, 5, repeated several times). Ive seen some posts about lock () and tried wrapping the assignment to x in it, but I clearly dont understand exactly how that works, and it didnt seem to in this case. TIA

private async void btnStart_Click(object sender, EventArgs e)
{
            
     var tskDataSetCodes = new List<Task>();
     Stopwatch s = new Stopwatch();
     int x = 99;
     for (int i = 0; i < 6; i++)
     {
          x = i;
          s.Start();
          Task kickoffTasks = new Task(() => ExtractDataSetCode(x)); 
                
          System.Diagnostics.Debug.WriteLine("DataSet : " + x + "Task: " + kickoffTasks.Id);  
          kickoffTasks.Start();
                
          tskDataSetCodes.Add(kickoffTasks);
     }
     await Task.WhenAll(tskDataSetCodes);
     s.Stop();
     var tasktime = s.ElapsedMilliseconds;

     System.Diagnostics.Debug.WriteLine("Application Completed" + tasktime);
}
       
static async void ExtractDataSetCode(int a)
{
     System.Diagnostics.Debug.WriteLine("ExtractDataSetCode: " + a + " on thread: " + Thread.CurrentThread.ManagedThreadId);  
     var tasks = new List<Task>();

     for (var count = 1; count <= 10; ++count)
     {

          Task queryTasks = new Task(() => queryProcess(a), TaskCreationOptions.AttachedToParent);
          queryTasks.Start();
          tasks.Add(queryTasks);
     }
     await Task.WhenAll(tasks);
}

static void queryProcess(int z)
{
     System.Diagnostics.Debug.WriteLine("Starting queryProcess for dataset: " + z + " on thread: " + Thread.CurrentThread.ManagedThreadId);

     Thread.Sleep(10000);

     //System.Diagnostics.Debug.WriteLine("Ending queryProcess for dataset: " + i + " on thread: " + Thread.CurrentThread.ManagedThreadId);
}


adveach
  • 55
  • 1
  • 8
  • What's the actual output and what output do you expect? Please share by adding it to the question to clarify the problem. – Julian Feb 07 '23 at 16:45

1 Answers1

1

x here is "captured", meaning the same variable is used by all instances of the loop - with the value being a race condition between the loop and the task execution; move it inside the loop:

 for (int i = 0; i < 6; i++)
 {
      int x = i;
      // ...
 }

You might also want to use Task.Run instead of new() and Start():

 s.Start();
 for (int i = 0; i < 6; i++)
 {
      int x = i;
      tskDataSetCodes.Add(Task.Run(() => ExtractDataSetCode(x)));
 }
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Argh. That makes sense. Thanks! FWIW...I was originally using Task.Run, but since I need to spawn child tasks that are attached to the parent (or rather will need to in my application this represents), I had to switch to NEW() and START(). – adveach Feb 07 '23 at 18:56
  • @adveach the scenarios in which attached tasks makes sense are *incredibly* niche; are you sure you need that? – Marc Gravell Feb 08 '23 at 09:29