任务延续会扰乱参考文献

时间:2013-11-07 07:35:37

标签: c# asynchronous task

所以我的一些代码就像这样异步调用

Task.Run(() => DoSomethingAsync());

DoSomethingAsync本身调用DoSomething2Async,看起来像这样

private void DoSomething2Async()
{
    Something something = new Something(3);
    Random rand = new Random();
    for (int i = 0; i < 3; i++)
    {
        something.a = rand.Next(1000);

        var task = new Task<int>(()
            => Calculate());

        something.ContinueWith((t)
            => CalculateContinuation(something, task.Result));

        task.Start();
    }

    MessageBox.Show("Do Something2 is done");
}

这是Calculate()方法

private int Calculate()
{
    for (int i = 0; i < 100000000; i++)
    {
        var a = 5; // imitate some job
    }

    return new Random().Next();
}

这是CalculateContinuation()方法

private void CalculateContinuation(Something something, int b)
{
    MessageBox.Show(something.a.ToString(), b.ToString());
}

这是类Something

class Something : ICloneable
{
    public int a;

    public Something(int aa)
    {
        a = aa;
    }

    public object Clone()
    {
        Something clone = new Something(a);

        return clone;
    }
}

如您所见,Calculate被调用3次,CalculateContinuation也会被调用3次,我想传递给CalculateContinuation 2参数,其中一个是调用之前配置的对象(在这种情况下)它是某事物的实例),第二个是Calculate方法的结果。现在的问题是Calculate的结果对于每次调用都是不同的(因为它是随机的)并且something.a对于每个调用也应该是不同的,因为它也是随机的,但每次调用{{1} } hit something指的是在CalculateContinuation的循环的最后一次迭代中配置的Something实例。 (如果它在循环之前被击中我认为它将引用当时配置的对象)。我的意思是我得到DoSomething2Async MessageBoxes的结果不同但Calculate不是。我一直试图解决这个问题两天我不知道该怎么做。我试图传递something.a的克隆我试图将something添加到集合中并在每次迭代时传递最后一个,但没有任何东西给我所需的结果。可能有人有这样的问题。在这种情况下解决方案是什么。提前谢谢

修改

人类可读代码

something

RegisterAllUsers就像这样调用

private void RegisterAllUsers()
{
    Person person = new Person(string.Empty);

    for (int i = 0; i < 3; i++)
    {
        person.Name = "Some name"; // different on each iteration

        // create registration task
        var registrationTask = new Task<bool>(()
            => RegisterUser(person));

        // assign continue with, first parameter is person itself and second is the result of RegisterUse
        registrationTask.ContinueWith((task)
            => RegistrationCallback(person, registrationTask.Result));

        registrationTask.Start();
    }
}

private bool RegisterUser(Person person)
{
    // do registration stuff

    return true; // or false if failes 
}

private void RegistrationCallback(Person person, bool succeded)
{
    // when this method executed the reference of person is whatever was set in RegisterAllUsers
    // for the last time, but i want to have reference to the user which was configured on each iteration

    // suppose 1st user is Steve 2nd is Bob and 3rd is Jack
    // when this methid is hit the name of the user is Jack on all 3 callbacks but the succeded parameter
    // is whatever the RegisterUser returned

    // update registered user's status
}

1 个答案:

答案 0 :(得分:1)

关于您编辑的部分代码:

Person只有一个实例:person。然后用i开始循环。循环为每个person.Name填写i,同时启动任务。不幸的是,在启动任务之前,foreeach循环已完成,person实例仅包含最后指定的值。因此,您有三个计划任务,每个计划都需要一个person个实例,该实例只有最后一个值分配给Name,因为Name取决于i我从问题描述。

要解决此问题,请为每个任务创建Person的实例,并在循环中使用j变量(闭包问题):

for (int i = 0; i < 3; i++)
{
    int j = i;
    Person person = new Person(string.Empty);
    person.Name = "Some name"; // depends on j this time rather on i
....