Scenario: An asynchronous task in a loop executes a method containing arguments that change as the program continues:
while(this._variable < 100)
{
this._variable++;
var aTask = Task.Factory.StartNew(() =>
{
aList.add(this._variable);
update(this._savePoint);
});
}
If the loop runs faster than the tasks complete, will the list add the current value of the variable or is the variable saved locally and the original value added?
Closures close over variables, not values. Therefore, incrementing _variable
can alter the behavior of the task that refers to it.
You can prevent this by making a local copy:
while (this._variable < 100)
{
this._variable++;
int local = _variable;
var aTask = Task.Factory.StartNew(() =>
{
aList.add(local);
update(this._savePoint);
});
}
Or you could pass the value to the task as state:
while (this._variable < 100)
{
this._variable++;
var aTask = Task.Factory.StartNew(object state =>
{
aList.add((int)state);
update(this._savePoint);
}, this._variable);
}
These both work by copying the value of _variable
to a new temporary variable. In the first case the local
variable is defined inside the scope of the loop, so you get a new one for every iteration. In the second case, you make a copy of the value of _variable
when you pass it to the Task as the state
argument. If _variable
were a reference type, these solutions wouldn't work; you'd have to perform a clone.