Fei*_*Fei 8 .net c# 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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
据说标记m_value 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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
一个相关的问题是本书中的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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
由于ECMA-CLI规定"互锁操作执行隐式获取/释放操作",在这种情况下我们是否还需要易失性?
首先,搞乱 volatile 真的很难,所以不要太随意!但是,这是对您的问题的一个非常接近的答案,我认为每个人都应该在使用关键字 , 之前阅读这篇文章,volatile
并且绝对在开始使用VolatileRead
,VolatileWrite
和 之前阅读MemoryBarrier
。
第一个链接中的答案是:不,您不需要使用 volatile,您只需要System.Threading.Thread.MemoryBarrier()
在分配新值之前使用 RIGHT。这是因为release_fence
使用 volatile 关键字时隐含的含义确保它已完成向主内存的写入,并且在完成之前无法执行读/写操作。
那么,Thread.VolatileWrite() 的作用是什么?它执行的功能是否与我们从 'volatile' 关键字获得的功能相同?好吧,这是该函数的完整代码:
public static void VolatileWrite (ref int address, int value)
{
MemoryBarrier(); address = value;
}
Run Code Online (Sandbox Code Playgroud)
是的,它在分配您的值之前调用 MemoryBarrier,这就足够了!