关于任务继续的问题

时间:2011-08-31 04:19:17

标签: c# .net multithreading task-parallel-library

任务1:

public Task SendMail(string email)
 {
  ...
 }

TASK2:

public Task<int> SaveToDB(User user)
 {
  ...
 }

我需要做什么:

  1. 当task1失败时,应返回“发送失败”信息;
  2. 当task1成功时,task2开始。
  3. 当task2失败时,应返回“保存失败”信息。
  4. 当task2成功时,应返回“保存成功”信息。
  5. 请帮我找一个解决方案:

    public Task<string> SendAndSave(User user){
    var task1 = SendMail(user.Email);
    var task1Failed = task1.ContinueWith(t =>   
    {
         var e = task1.Exception;
         return "Send Failed";
    }, 
    TaskContinuationOptions.OnlyOnFaulted | 
    TaskContinuationOptions.ExecuteSynchronously);
    
    var task2 = task1.ContinueWith(t =>
    {
        var save = SaveToDB(user);
        try
        {
            int result = save.Result;
            return "Save Succeeded"; 
          }
         catch(AggregateException ae)
         {
              return "Save Failed";
          }
          },
          TaskContinuationOptions.NotOnFaulted); 
    
     return Task.Factory.ContinueWhenAny(new[] {task1Failed, task2}, t => t.Result);
     }
    

    当我运行它时,我收到一个错误。

    我把它调用为:

    var result = SendAndSave(user).Result;

    错误发生在:

    public Task<string> SendAndSave(User user)
    {
          ...
          return Task.Factory.ContinueWhenAny(new[] {task1Failed, task2}, t => t.Result);   //Here: A task was cancelled
     }
    

    调试后,我有两个问题:

    • Q1:在task1之后,task1Failed,task2被创建,每个值都是 CreationOption属性为“none”,尽管其状态为 “WaitingForActivation”。似乎所有的延续选择都是 无效。

    • Q2:对于Task.Factory.ContinueWhenAny的任务(new [] {task1Failed, task2},t =&gt; t.Result),让我们把它命名为“factoryTask”,即 ContinueWhenAny似乎无效。在内部放了一个断点 每个task1Failed,task2和factoryTask,我偶尔可以看到 尽管如此,工厂中的断点首先被击中了 应该在task1Failed或task2完成后进行命中。

    有人可以帮忙吗?感谢。

1 个答案:

答案 0 :(得分:1)

虽然我不完全理解你的问题,但我理解这里的问题,基本上你总是有task1Failed或task2完成但不是两者都有,而另一个将被取消! 所以在WaitOnAny调用中,如果它发现其中一个任务已被取消,它将崩溃,这实际上取决于tasks参数的顺序,所以在上面的例子中你首先传递task1failed,所以如果这个任务完成,ContinueWhenAny将工作很好,因为它检查的第一个任务已经完成,所以它不会检查另一个,但如果task1Failed没有运行,所以它处于取消状态,ContinueWhenAny将抛出!

要避免这种情况,您需要使用TaskCompletetionSource,并且运行的任务将设置值,然后在结束时返回tcs.Task.Result

public Task<string> SendAndSave(User user){
var tcs = new TaskCompletionSource<string>();
var task1 = SendMail(user.Email);
var task1Failed = task1.ContinueWith(t =>   
{
     var e = task1.Exception;
     tcs.TrySetResult("Send Failed");
}, 
TaskContinuationOptions.OnlyOnFaulted | 
TaskContinuationOptions.ExecuteSynchronously);

var task2 = task1.ContinueWith(t =>
{
    var save = SaveToDB(user);
    try
    {
        int result = save.Result;
        tcs.TrySetResult("Save Succeeded"); 
    }
    catch(AggregateException ae)
    {
       tcs.TrySetResult("Save Failed"); 
    }
},TaskContinuationOptions.NotOnFaulted); 

 return tcs.Task.Result;
}