再次双重检查锁定和C# [英] Again double-checked locking and C#

查看:186
本文介绍了再次双重检查锁定和C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Recently I have been refactoring some of my C# code and I found a few double-checked locking practices taking place. I didn't know it was a bad practice back then and I really want to get rid of it.

的问题是,我应该延迟初始化类并经常大量线程的访问。我也不想初始化移动到一个静态初始化,因为我计划使用弱引用保持初始化的对象,从留在记忆太长。然而,如果需要的话,我想复活,确保该物体发生在一个线程安全的方式。

The problem is that I have a class that should be lazily initialized and frequently accessed by lots of threads. I also do not want to move the initialization to a static initializer, because I am planning to use a weak reference to keep the initialized object from staying too long in the memory. However, if needed, I want to 'revive' the object ensuring this happens in a thread-safe manner.

我如果在C#中使用ReaderWriterLockSlim并输入一个奇怪第一检查前UpgradeableReadLock,然后如果必要的输入的写锁用于初始化将是可接受的解决方案。下面是我心中有什么:

I was wondering if using a ReaderWriterLockSlim in C# and enter an UpgradeableReadLock before the first check, and then if necessary enter a write lock for the initialization would be an acceptable solution. Here is what I'm having in mind:

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    
    }
}

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

My point is that no other thread should try to initialize the item once again, while many threads should read simultaneously once the value is initialized. The upgradeable read lock should block all readers if the write lock is acquired, therefore while the object is being initialized, the behavior will be similar to having a lock statement where the upgradeable read lock begins. After the initialization the Upgradeable read lock will permit multiple threads therefore the performance hit of waiting each thread will not be present.

我也看过一篇文章的这里说挥发导致内存壁垒被自动插入前读取和写入后,所以我想只有一个手动定义屏障读出和写入之间将足以确保_valueReference对象被正确读出。我会很高兴地感谢您的建议和批评,使用这种方法。

I also read an article here saying that volatile causes memory barriers to be automatically inserted before read and after write, so I assume only one manually defined barrier between the read and the write will be enough to ensure that the _valueReference object is correctly read. I will gladly appreciate your advices and criticism for using this approach.

推荐答案

要强调这一点@Mannimarco做:如果是这样的只有接入点的价值,它看起来是这样,那么你的整个ReaderWriterLockSlim设置是不超过一个简单的Monitor.Enter / Monitor.Leave方法更好。这是一个复杂得多,但。

To emphasize the point @Mannimarco makes: if this is the only access point to the Value, and it looks that way, then your whole ReaderWriterLockSlim setup is no better than a simple Monitor.Enter / Monitor.Leave approach. It is a lot more complicated though.

因此,我相信下面的代码在功能和效率等同的:

So I believe the following code is equivalent in function and efficiency:

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#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆