1

The payload.DaysRemaining value gets reset to zero each time the Process method gets invoked.

I understand that the method containing the task to be executed will execute independent of the task object declared within it which results in the variables declared within the containing method to loose state.

So how do I maintain state within a for loop using tasks that rely on method scoped variables?

private static async Task Assign(Payload payload)
{
    var duration = payload.DaysRemainingToJobsDue.First().Key;
    var tasks = new List<Task>();

    for (var daysRemaining = duration; daysRemaining >= 0; daysRemaining--)
    {
        payload.DaysRemaining = daysRemaining;

        var task = new Task(() =>
        {
            Process(payload);
        });

        tasks.Add(task);
        task.Start();
    }

    Task.WaitAll(tasks.ToArray());
    return;
}

private static void Process(object state)
{
    var payload = state as Payload;

    foreach (var job in payload.Jobs)
    {
        var compareResult = job.DueDate.CompareTo(DateTime.Now.AddDays(payload.DaysRemaining));

        var withinRange = compareResult <= 0;

        if (withinRange)
        {
            HashSet<Job> existingJobsDue = null;
            var pendingJobsExist = payload.DaysRemainingToJobsDue.TryGetValue(payload.DaysRemaining, out existingJobsDue);

            if (pendingJobsExist)
            {
                existingJobsDue.Add(job);
            }
            else
            {
                existingJobsDue = new HashSet<Job>();
                existingJobsDue.Add(job);
            }

            payload.DaysRemainingToJobsDue[payload.DaysRemaining] = existingJobsDue;
        }
    }
}
Scott Nimrod
  • 11,206
  • 11
  • 54
  • 118

1 Answers1

0

This effect is called closure.

What you need to do is create a local copy of your variable inside the lambda expression being passed to newly created Task:

var task = new Task(() =>
{
    var localPayload = payload;
    Process(localPayload);
});
Community
  • 1
  • 1
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • -1: You're on the right track, but this implementation would only work if the `Payload` type is a `struct`. I don't believe enough information was presented to make that assumption. – Sam Harwell Oct 13 '14 at 10:21
  • @Sam This has nothing to do with structs. Why would you think that? – Yuval Itzchakov Oct 13 '14 at 10:59
  • @Sam Reference type closure have a similar effect: http://lostechies.com/derickbailey/2009/02/23/closures-in-c-variable-scoping-and-value-types-vs-reference-types/ – Yuval Itzchakov Oct 13 '14 at 11:36
  • 1
    I think the part you missed is the line `payload.DaysRemaining = daysRemaining;`. If the same instance of `payload` gets used by all of the tasks, there is no way to have per-task assignment of the `DaysRemaining` property. – Sam Harwell Oct 13 '14 at 12:13
  • 1
    That's why he's always seeing the last instance of `payload` which has `daysRemaining` value equal to 0. I assume he's always getting the last reference – Yuval Itzchakov Oct 13 '14 at 12:26