首页 > 解决方案 > Task.IsCompleted 使用缓存标志的原因是什么?

问题描述

我正在查看 System.Threading.Tasks(.NET 标准 2.0)中 Task 的一些实现细节,我遇到了这段有趣的代码:

internal volatile int m_stateFlags;

...

public bool IsCompleted
{
  get
  {
    int stateFlags = m_stateFlags; // enable inlining of IsCompletedMethod by "cast"ing away the volatiliy
    return IsCompletedMethod(stateFlags);
  }
}

// Similar to IsCompleted property, but allows for the use of a cached flags value
// rather than reading the volatile m_stateFlags field.
private static bool IsCompletedMethod(int flags)
{
  return (flags & TASK_STATE_COMPLETED_MASK) != 0;
}

我从阅读 C# 参考指南中了解到 volatile 是为了防止编译器/运行时/硬件优化导致对字段的读/写重新排序。为什么在这种特定情况下将字段指定为 volatile 只是为了在通过将字段分配给变量来读取字段时忽略波动性?

这似乎是有意的,但我不清楚意图背后的原因。另外,“抛弃”波动性是一种常见的做法吗?在哪些情况下我想这样做与我绝对想避免它的情况?

非常感谢任何有助于我更清楚地理解这段代码的信息。

谢谢,

标签: c#.nettasktask-parallel-libraryvolatile

解决方案


volatileand的语法糖Volatile.ReadVolatile.Write。它确保任何 CPU 将同时看到相同的数据。

所以它只读取一次 volatile 变量。那么这可能会在属性,方法中多次使用(失去易失性)。所以看起来它拍摄了变量的快照并对其值进行了几次计算。

internal volatile int m_stateFlags;

public bool IsCompleted
{
  get
  {
      int stateFlags = m_stateFlags;
      return IsCompletedMethod(stateFlags);
  }
}

推荐阅读