一文带你了解.Net混合锁和lock语句

在这里插入图片描述
本文主要讲解.Net基于Monitor.Enter和lock实现互斥锁


Monitor.Enter实现

相比前面的锁来说,混合锁的性能更高,任何引用类型的对象都可以做为锁对象,不需要事先创建指定类型的实例,并且设计的非托管的资源由.Net运行时自动释放,不需要手动调用释放函数,获取和释放混合锁需要使用System.Threading.Monitor类中的函数。使用Monitor使用混合锁的例子如下:

using System;
using System.Threading;

namespace MixedLockDemo
{
    /// <summary>
    /// 混合锁Demo
    /// </summary>
    public static class NitiveLockDemo
    {
        private static readonly object _lock = new();
        private static int _counterA = 0;
        private static int _counterB = 0;

       
        public static void IncrementCounters()
        {
            //定义变量
            var lockObject = _lock;
            bool lockTaken = false;
            try
            {
                Console.WriteLine($"开始执行锁前的数值:{_counterA},{_counterB}");
                // 获取锁
                Monitor.Enter(_lock, ref lockTaken);
                ++_counterA;
                ++_counterB;

            }
            finally
            {
                //如果锁wei
                if (!lockTaken)
                {
                    Monitor.Exit(lockObject);
                }
            }
        }

     
        public static void GetCounters(ref int counterA, ref int coubterB)
        {
            //定义变量
            var lockObject = _lock;
            bool lockTaken = false;
            try
            {
                Monitor.Enter(lockObject, ref lockTaken);
                counterA = _counterA;
                coubterB = _counterB;
            }
            finally
            {
                if (!lockTaken)
                {
                    Monitor.Exit(lockObject);
                }
            }
        }
    }
}


lock实现

C# 调用lock语句来简化System.Threading.Monitor类获取和释放锁的代码。以下是使用lock的实例

namespace MixedLockDemo
{
    /// <summary>
    /// 封装后的lock语句使用
    /// </summary>
    public static class PackageingLockDemo
    {
        private static readonly object _lock = new();
        private static int _counterA = 0;
        private static int _counterB = 0;

        /// <summary>
        /// 增加
        /// </summary>
        public static void IncrementCounters()
        {
            lock (_lock)
            {
                ++_counterA;
                ++_counterB;
            }
        }

        /// <summary>
        /// 获取
        /// </summary>
        /// <param name="counterA"></param>
        /// <param name="coubterB"></param>
        public static void GetCounters(ref int counterA, ref int coubterB)
        {
            lock (_lock)
            {
                counterA = _counterA;
                coubterB = _counterB;
            }
        }
    }
}

概念

混合锁的特征是在获取失败后像自旋锁一样重试一定的次数,超过一定次数后再安排线程进入等待状态,


混合所的好处是,如果第一次获取锁失败,但其他线程马上释放了锁,当前线程在下一轮重试可以获取成功,不需要执行毫秒级的线程调度处理;如果其他线程在短时间内没有释放锁,线程会在超过重试次数后进入等待状态,以避免消耗CPU资源,因此混合锁适用于大部分场景。


所有引用类型的对象都可以作为锁对象的原理是,引用类型的对象都有一个32位(4字节)的对象头,对象头的位置在对象地址之前,例如对象的内容在内存地址中0×7fff2008时,对象头的地址在0×7fff2004。在32位的对象头中,高6位用于储存标志,低26位储存的内容根据标志而定,可以存储当前获取该锁的线程Id和进入次数(用入实现可重入),也可以储存同步块索引。


同步块是一个包含所属线程对象,进入次数和事件对象的对象。事件对象可用于让线程进入等待状态和唤醒线程,同步块会按需要创建(如果只是用自旋锁可获取锁则无需创建)并自动释放,.Net运行时内部有一个储存同步块的数组,同步块索引指的是同步块在这个数组中的索引.

释放锁和获取锁流程图


本文基于.Net Core底层入门总结内容

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧🙂
个人微信

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值