gpt4 book ai didi

c# - 再次仔细检查锁定和 C#

转载 作者:太空狗 更新时间:2023-10-29 23:26:08 26 4
gpt4 key购买 nike

最近我一直在重构我的一些 C# 代码,我发现了一些双重检查的锁定实践。当时我不知道这是一种不好的做法,我真的很想摆脱它。

问题是我有一个类应该延迟初始化并且经常被很多线程访问。我也不想将初始化移动到静态初始化器,因为我打算使用弱引用来防止初始化对象在内存中停留太久。但是,如果需要,我想“恢复”对象以确保以线程安全的方式发生。

我想知道是否在 C# 中使用 ReaderWriterLockSlim 并在第一次检查之前输入 UpgradeableReadLock,然后在必要时为初始化输入写锁是否是一个可接受的解决方案。这是我的想法:

public class LazyInitialized
{
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

private volatile WeakReference _valueReference = new WeakReference(null);
public MyType Value
{
get
{
MyType value = _valueReference.Target as MyType;
_lock.EnterUpgradeableReadLock();
try
{
if (!_valueReference.IsAlive) // needs initializing
{
_lock.EnterWriteLock();
try
{
if (!_valueReference.IsAlive) // check again
{
// prevent reading the old weak reference
Thread.MemoryBarrier();
_valueReference = new WeakReference(value = InitializeMyType());
}
}
finally
{
_lock.ExitWriteLock();
}
}
}
finally
{
_lock.ExitUpgradeableReadLock();
}
return value;
}
}

private MyType InitializeMyType()
{
// code not shown
}
}

我的观点是,没有其他线程应该尝试再次初始化该项目,而一旦值被初始化,许多线程应该同时读取。如果获取了写锁,可升级读锁应该阻止所有读者,因此在初始化对象时,行为将类似于在可升级读锁开始的地方有一个锁定语句。初始化后,可升级读锁将允许多个线程,因此不会出现等待每个线程的性能损失。

我还看了一篇文章here说 volatile 会导致在读取之前和写入之后自动插入内存屏障,所以我假设在读取和写入之间只有一个手动定义的屏障就足以确保正确读取 _valueReference 对象。我很乐意感谢您对使用此方法提出的建议和批评。

最佳答案

要强调@Mannimarco 提出的观点:如果这是对值的唯一访问点,并且看起来是那样,那么您的整个 ReaderWriterLockSlim 设置并不比简单的 Monitor.Enter/Monitor.Leave 方法好。不过要复杂得多。

所以我认为下面的代码在功能和效率上是等价的:

private WeakReference _valueReference = new WeakReference(null);
private object _locker = new object();

public MyType Value
{
get
{
lock(_locker) // also provides the barriers
{
value = _valueReference.Target;

if (!_valueReference.IsAlive)
{
_valueReference = new WeakReference(value = InitializeMyType());
}
return value;
}
}
}

关于c# - 再次仔细检查锁定和 C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6334731/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com