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