-1

In my program I currently have a structure similar to this:

for (int i=0; i<MyCollection.Count; i++)
{
    Task.Factory.StartNew(()=>
    {
        DoStuffWith(MyCollection[i]);
        DoEvenMoreStuffWith(MyCollection[i]);
    });
}

It does not work properly because functions DoStuffWith() and DoEvenMoreStuffWith() take more time to complete than i++, hence one of these will usually modify the wrong element of the collection.

I know I can't do int a = i before the Task.Factory because it's gonna be the same, really.

How do I make sure each thread works with their own index exclusively?

P.S.: Sorry, I tried looking for an answer here but I don't even know how to google it properly. I know it's something that has to do with reference types and value types, but I've never used them around Task.Factory before.

weston
  • 54,145
  • 21
  • 145
  • 203
Cowbless
  • 93
  • 12

1 Answers1

2

If you use a standard for loop, you can keep a local copy of the variable within the closure of the loop body (just as you suggested was not possible), and this closure will be captured by the body of your deferred code.

So:

for (int i=0; i<MyCollection.Count; i++)
{
    var a = i;
    Task.Factory.StartNew(()=>
    {
        DoStuffWith(MyCollection[a]);
        DoEvenMoreStuffWith(MyCollection[a]);
    });
}

However, there is a better way.

Recently(ish), the c# language was changed to close over the loop variable in foreach loops.

So, unless you're stuck with 2012-era tooling, now you can:

foreach(var item in MyCollection)
{
    Task.Factory.StartNew(()=>
    {
        DoStuffWith(item);
        DoEvenMoreStuffWith(item);
    });
}

without this issue happening.

As an aside, do you know the difference between Task.Factory.StartNew and Task.Run? You should do.

spender
  • 117,338
  • 33
  • 229
  • 351
  • Thank you for summarizing it! Foreach doesn't work for me because I don't use all elements so I need to keep track of the indices. I left this detail out because it was immaterial to the question. And I'll give a poke to that article about Tasks. Appreciate the advice. – Cowbless Mar 25 '18 at 13:03
  • @TorlanDelta I tend to prefer `foreach` because, with the language changes that were made, it went from requiring mutable state to becoming a purer functional construct. While this might not be applicable to your case, I'd filter the collection before iterating if I wanted to deal with a subset. – spender Mar 25 '18 at 13:11