Lock usage and efficiency analysis (C#)

For the four methods of no Lock, Lock, ReadWriterLock, and ReadWriterLockSlim, the reading efficiency is tested under the condition of continuous writing (the atomic operation Interlocked has many modifications for int, double, etc., and the scope of use is limited, so this article The article has not been tested)

First let’s talk about the conclusion:

Lock type Run times per minute 1 Run times per minute 2 Run times per minute 3 Average
No lock 97998684 80541036 97074298 91871339.3
lock 81270863 71114328 87351084 79912091.7
ReadWriterLock 74970270 89350032 85879937 83400079.7
ReadWriterLockSlim 85942306 92206133 88802621 88983686.7

Operating environment:

Operating efficiency: no lock>ReadWriteLockSlim>ReadWriterLock>lock

1. No Lock

Multi-threaded reading and writing can easily cause data errors. This is not to reproduce data errors, but to test the reading efficiency of the lock-free method.

private IntellVega.Project.Develop.Models.CustomSetting Compensation
{
    get
    {
        return _compensation;
    }
    set
    {
        _compensation = value;
    }
}

private void InitCommand()
{
    WriteCommand = new RelayCommand(Write);
    ReadCommand = new RelayCommand(Read);
}

private void Write()
{
    Task.Run(() =>
    {
        while(true)
        {
            IntellVega.Project.Develop.Models.CustomSetting compensation = new IntellVega.Project.Develop.Models.CustomSetting();
            Random random = new Random();
            compensation.FocusCompensation = random.NextDouble();
            Compensation = compensation;
        }
    });
}

private void Read()
{
    Time = 0;
    Task.Run(() =>
    {
        Stopwatch sw = Stopwatch.StartNew();
        while(true)
        {
            if (sw.ElapsedMilliseconds > 60 * 1000) { break; }
            double d = Compensation.FocusCompensation;
            Time + + ;
        }
    });
}

2. lock

Lock is a simple and easy-to-use thread synchronization method. It achieves synchronization by acquiring a mutex lock for a given object. It can guarantee that when a thread is in the critical code section, another thread will not come in. It can only wait until the thread object is released, which means that the thread has left the critical section.

The parameters of lock must be objects based on reference types, not basic types like bool, int, etc. This cannot be synchronized at all. The reason is that the parameters of lock must be objects. If int is passed in, a boxing operation will inevitably occur, so that every The second lock will be a new and different object. It is best to avoid using public types or object instances that are not controlled by the program, because this is likely to cause deadlock. In particular, do not use strings as lock parameters, because strings are “persisted” by the CLR, which means that there is only one instance of a given string in the entire application, so it is easier to cause deadlock. It is recommended to use private or protected members as parameters that are not “persistent”. In fact, some classes already provide members specifically for being locked. For example, the Array type provides SyncRoot, and many other collection types also provide SyncRoot.

Therefore, when using lock, you should pay attention to the following points:

1. If an instance of a class is public, it is best not to lock(this). Because people who use your class may not know that you use lock. If they create a new instance and lock this instance, it will easily cause a deadlock.

2. If MyType is public, do not lock(typeof(MyType))

3. Never lock a string

private IntellVega.Project.Develop.Models.CustomSetting Compensation
{
    get
    {
        lock(_obj)
        {
            return _compensation;
        }
    }
    set
    {
        lock(_obj)
        {
            _compensation = value;
        }
    }
}

3. ReadWriterLock method

When considering resource access, we will inertly implement a lock mechanism on the resource. However, in some cases, we only need to read the data of the resource instead of modifying the data of the resource. In this case, we can obtain the exclusive right of the resource. It will undoubtedly affect the operating efficiency, so .Net provides a mechanism. When using ReaderWriterLock for resource access, if the resource does not obtain the exclusive right to write at a certain moment, you can obtain multiple read access rights and a single write access right. Exclusive rights. If exclusive rights for writing have been obtained at a certain moment, other read access rights must wait.

private IntellVega.Project.Develop.Models.CustomSetting Compensation
{
    get
    {
        try
        {
            _readWriterLock.AcquireReaderLock(1000);
            return _compensation;
        }
        finally
        {
            _readWriterLock.ReleaseReaderLock();
        }
    }
    set
    {
        _readWriterLock.AcquireWriterLock(1000);
        _compensation = value;
        _readWriterLock.ReleaseWriterLock();
    }
}

4. ReadWriterLockSlim method

ReaderWriterLockSlim is similar to ReaderWriterLock, except that the rules for recursion, promotion, and degradation of lock states are simplified. ReaderWriterLockSlim avoids several potential deadlock situations. Additionally, ReaderWriterLockSlim performs significantly better than ReaderWriterLock. ReaderWriterLockSlim is recommended for all new development work.
Excerpted from: Link: https://www.jianshu.com/p/a3e69ed17c8a

private IntellVega.Project.Develop.Models.CustomSetting Compensation
{
    get
    {
        try
        {
            _readWriterSlimLock.EnterReadLock();
            return _compensation;
        }
        finally
        {
            _readWriterSlimLock.ExitReadLock();
        }
    }
    set
    {
        try
        {
            _readWriterSlimLock.EnterUpgradeableReadLock();
            try
            {
                _readWriterSlimLock.EnterWriteLock();
                _compensation = value;
            }
            finally
            {
                _readWriterSlimLock.ExitWriteLock();
            }
        }
        finally
        {
            _readWriterSlimLock.ExitUpgradeableReadLock();
        }
    }
}

–END