Task.Faulted 和 Task.Exception

Task.Faulted and Task.Exception

TaskStatus Enum or Task.Exception MSDN 似乎都没有明确说明:

是否 TasksStatus.Faulted 总是暗示着 Task.Exception != null(而 TaskStatus != Faulted 总是暗示着 Task.Exception == null)?

是的,Task.IsFaulted 的文档明确指出:

If IsFaulted is true, the task's Status is equal to Faulted, and its Exception property will be non-null.

参考源代码几乎肯定列出了。在 FinishStageTwo 中,我们看到内部 m_state 仅在记录异常时才设置为故障:

  if (ExceptionRecorded)
  {
      completionState = TASK_STATE_FAULTED;
      ...
  }
  ...
  Interlocked.Exchange(ref m_stateFlags, m_stateFlags | completionState);

因此只有在记录异常时状态才会出错。

但是,Exception getter 确实提到了一个可能的竞争条件:

// Only return an exception in faulted state (skip manufactured exceptions)
// A "benevolent" race condition makes it possible to return null when IsFaulted is
// true (i.e., if IsFaulted is set just after the check to IsFaulted above).

只有当 IsFaulted 变为真时才会出现此竞争条件,因为 Exception getter 是 运行。

因此,如果在任务执行时调用以下代码,则可能会失败:

 var ex = task.Exception;
 var faulted = task.IsFaulted;
 if (faulted)
     Assert.IsTrue(ex != null);

但是以下永远不会失败:

 var faulted = task.IsFaulted;
 var ex = task.Exception;
 if (faulted)
     Assert.IsTrue(ex != null);

如果您已经完成等待任务完成,第一种情况也永远不会失败。这可能就是为什么他们将其标记为“仁慈”并将其留在其中的原因。受其影响的代码量非常小。