【问题标题】:Passing a Task instance to the task's delegate将 Task 实例传递给任务的委托
【发布时间】:2011-12-20 11:49:53
【问题描述】:

我有一个长时间运行的任务,它使用回调以增量方式提供数据(而不是最后的单个 ContinueWith() 回调)。

我希望能够在此回调中将 Task 对象传回用于任务识别目的(使用 Task.CurrentId)

但是,我不知道如何将 Task 对象传递给任务委托。执行此操作似乎没有重载,并且我不能使用闭包来执行此操作,因为此时未定义任务对象。

例如。

public Task StartDoingSomeStuff(CallbackDelegate callback)
{
    Task task = Task.Factory.StartNew(() =>
    {
         while(whatever)
         {
             var results = DoSomeStuff();
             callback(results, task); //CS0165. How do I get hold of the task?
         }
    });

    return task;
}

给予:

错误 CS0165:使用未分配的局部变量“任务”

【问题讨论】:

    标签: c# callback task task-parallel-library


    【解决方案1】:

    拆分声明变量并将任务分配给两个语句。确保在分配任务之前不要使用该变量:

    public Task StartDoingSomeStuff(CallbackDelegate callback)
    {
        var gate = new object();
        lock (gate)
        {
            Task task = null;
            task = Task.Factory.StartNew(() =>
            {
                lock (gate)
                {
                    while (whatever)
                    {
                        var results = DoSomeStuff();
                        callback(results, task);
                    }
                }
            });
            return task;
        }
    }
    

    【讨论】:

    • +1 我只是在写同样的东西。 :) 我还将signal.Wait(); 移动到DoSomeStuff() 之后的行,以延迟锁定。
    • 与其使用ManualResetEventSlim signal,不如简单地使用lock 语句。在@Groo 发表评论后,我已经相应地改变了我的答案。
    • 同意,这更简单。我仍然可能只锁定callback 行,但性能差异很小。
    • callback 行处于循环中,因此lock 需要重复获取,而不仅仅是一次。
    【解决方案2】:

    另一种解决方案是创建一个任务键和一个将键映射到任务的字典,然后将键作为状态传递给任务操作:

    var taskMap = new Dictionary<object, Task>();
    var taskKey = new object();
    taskMap.Add(taskKey, Task.Factory.StartNew(key => { callback(results, key); }, taskKey));
    

    当然,您必须从密钥中查找任务,这可能适合您的场景,也可能不适合您的场景。

    【讨论】:

      【解决方案3】:

      这应该可行,尽管这是不好的做法:

      public Task StartDoingSomeStuff(CallbackDelegate callback)
      {
          Task task = null;
      
          task = Task.Factory.StartNew(() =>
          {
               while(whatever)
               {
                   var results = DoSomeStuff();
                   callback(results, task); //CS0165. How do I get hold of the task?
               }
          });
      
          return task;
      }
      

      【讨论】:

      • 如果你像dtb did一样同步,那就没问题了。这样你就冒着竞争条件的风险,后台线程在分配task之前完成它的工作。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-07
      • 2012-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多