Passing arguments with changing values to Task — B

2019-02-08 01:32发布

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?

1条回答
迷人小祖宗
2楼-- · 2019-02-08 01:51

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.

查看更多
登录 后发表回答