c# - .NET 中的双重检查锁定需要什么样的 'volatile' 操作

标签 c# .net multithreading

我从 Joe Duffy 的《Windows 上的并发编程》一书中获取了 DCL 的代码

class LazyInit<T> where T : class
{
private volatile T m_value;
private object m_sync = new object();
private Func<T> m_factory;
public  LazyInit(Func<T>  factory)  {  m_factory  =  factory;  }
public T value
{
  get
  {
    if (m_value == null)
    {
      lock (m_sync)
      {
        if (m_value == null)
        {
          m_value = m_factory();
        }
      }
    }
    return m_value;
  }
}
}

据说将 m_value 标记为 volatile 可以防止写入重新排序,这将导致其他线程获得“具有未初始化字段的非空对象”。如果问题只是因为可能的写入重新排序而发生,我是否可以只使用“ volatile 写入”而不是将文件标记为 volatile ,如下所示? (这段代码看起来有点尴尬,我只是想确定我们是否只能使用 volatile write 来代替)

class LazyInit<T> where T : class
{
private object m_value;
private object m_sync = new object();
private Func<T> m_factory;
public  LazyInit(Func<T>  factory)  {  m_factory  =  factory;  }
public T value
{
  get
  {
    if (m_value == null)
    {
      lock (m_sync)
      {
        if (m_value == null)
        {
          Thread.VolatileWrite(ref m_value, m_factory());
        }
      }
    }
    return (T)m_value;
  }
}
}

一个相关的问题是书中的 Interlocked 版本

class LazylnitRelaxedRef<T> where T : class
{
private volatile T m_value;
private Func<T> m_factory;
public LazylnitRelaxedRef(Func<T> factory) { m_factory = factory; }
public T Value
{
  get
  {
    if (m_value == null)
      Interlocked.CompareExchange(ref  m_value, m_factory(), null);
    return m_value;
  }
}
}

既然 ECMA-CLI 规范了“Interlocked operation perform implicit acquire/release operations”,在这种情况下我们还需要 volatile 吗?

最佳答案

首先,搞乱 volatile 真的很难,所以不要太松懈!但是,here是对您问题的非常接近的答案,here这篇文章我认为每个人都应该在使用关键字volatile之前阅读,并且绝对在开始使用VolatileReadVolatileWriteMemoryBarrier之前阅读

第一个链接中的答案是:不,您不需要使用 volatile,您只需要在分配新值之前使用 System.Threading.Thread.MemoryBarrier()。这是因为使用 volatile 关键字时隐含的 release_fence 确保它完成写入主内存,并且在完成之前不能执行读/写操作。

那么,Thread.VolatileWrite() 做了什么,它执行的功能是否与我们从“volatile”关键字获得的功能相同?那么,这是此函数的完整代码:

public static void VolatileWrite (ref int address, int value)
{
  MemoryBarrier(); address = value;
}

是的,它会在分配您的值之前调用 MemoryBarrier,这就足够了!

关于c# - .NET 中的双重检查锁定需要什么样的 'volatile' 操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8279575/

相关文章:

c# - WPF 验证错误 : How to show in separate TextBlock, 不在工具提示中

c# - 如何将 Windows 服务托管到 Windows Azure

c# - IIS 上的 Http 模块设置

java - 为什么使用 long literal 计算需要更多时间?

c# - 如何将字符串反序列化为对象(格式类似于对象表示法的字符串)

C# 填充字典值

c# - 在 Docker 中构建 .NET Framework 4.8 项目失败,错误代码为 "Reached end of stream before end of read"

c# - 在 WPF4 DataGrid 中水平滚动时性能较差

objective-c - 如何在macOS的非主线程上发生事件循环?

python - Pytorch C++ (Libtroch),使用操作间并行性