一文带你了解.net自旋锁(代码片段)

初夏的阳光丶 初夏的阳光丶     2022-11-29     811

关键词:

在这里插入图片描述
本文主要讲解.Net基于Thread实现自旋锁的三种方式


基于Thread.SpinWait实现自旋锁

实现原理:基于Test--And--Set原子操作实现
使用一个数据表示当前锁是否已经被获取 0表示未被索取,1表示已经获取 获取锁时会将_lock的值设置为1 然后检查修改前的值是否等于0,
优点:

  • 不使用Thread.SpinWait方法,重试的方法体会为空,CPU会使用它的最大性能来不断的进行赋值和比较指令,会浪费很大的性能,Thread.SpinWait提示CPU当前正在自旋锁的循环中,可以休息若干个时间周期
  • 使用自旋锁需要注意的问题,自旋锁保护的代码应该在非常短的时间内执行完成,如果时间过长,其他线程不断重试导致影响其他线程进行

缺点:

  • 当前实现没有考虑到公平性,如果多个线程同时获取锁失败,按时间顺序第一个获取锁的线程不一定会在释放锁后第一个获取成功,

代码实现:

 public static class ThreadSpinWaitDemo
    
        private static int _lock = 0;
        private static int _counterA = 0;
        private static int _counterB = 0;

        public static void IncrementCounters()
        
            while (Interlocked.Exchange(ref _lock, 1) != 0)
            
                Thread.SpinWait(1);
            

            ++_counterA;
            ++_counterB;
            Interlocked.Exchange(ref _lock, 0);
        

        public static void GetCounters(out int counterA, out int counterB)
        
            while (Interlocked.Exchange(ref _lock, 1) != 0)
            
                Thread.SpinWait(1);
            
            counterA = _counterA;
            counterB = _counterB;
            Interlocked.Exchange(ref _lock, 0);

        
    

基于SpinWaite实现自旋锁

特性是SpinOnce方法的次数,如果在一定次数以内并且当前逻辑核心所大于1,则调用Thread.SpinWait函数;如果超过一定次数或者当前环境逻辑核心数等于1,则交替使用
Thread.Sleep(0)和Thread.Yield函数,表示切换到其他线程,如果再超过一定次数,则让当前线程休眠
SpinWaite解决Thread.SpinWait中的两个问题

  • 如果自旋锁运行时间超长,SpinWaite可以提示操作系统切换到其他线程或者让当前线程进入休眠状态,
  • 如果当前环境只有一个核心逻辑,SpinWaite不会执行Thread.SpinWait函数,而是直接提示操作系统切换到其他线程,
 public static class ThreadSpinOnceDemo
    
        private static int _lock = 0;
        private static int _counterA = 0;
        private static int _counterB = 0;


        public static void IncrementCounters()
        
            var spinWait = new SpinWait();
            while (Interlocked.Exchange(ref _lock, 1) != 0)
            
                spinWait.SpinOnce();
            

            ++_counterA;
            ++_counterB;
            Interlocked.Exchange(ref _lock, 0);
        

        public static void GetCounters(out int counterA, out int counterB)
        
            var spinWait = new SpinWait();
            while (Interlocked.Exchange(ref _lock, 1) != 0)
            
                spinWait.SpinOnce();
            
            counterA = _counterA;
            counterB = _counterB;
            Interlocked.Exchange(ref _lock, 0);

        
    

基于SpinLock实现自旋锁

封装了SpinWaite的逻辑

SpinLock代码实现

 public class ThreadSpinLockDemo
    
        private static SpinLock _spinLock = new SpinLock();
        private static int _counterA = 0;
        private static int _counterB = 0;

        public static void IncrementCounters()
        
            bool lockTaken = false;
            try
            
                _spinLock.Enter(ref lockTaken);
                ++_counterA;
                ++_counterB;
            
            finally
            
                if (lockTaken)
                
                    _spinLock.Exit();
                
            
        

        public static void GetCounters(out int counterA, out int counterB)
        
            bool lockTaken = false;
            try
            
                _spinLock.Enter(ref lockTaken);
                counterA = _counterA;
                counterB = _counterB;
            
            finally
            
                if (lockTaken)
                
                    _spinLock.Exit();
                
            
        
    

简述 Thread.Sleep(0)和Thread.Yield的区别

  • 在Windows系统中 Thread.Sleep调用系统提供的SleepEx函数,Thread.Yield函数调用的是系统提供的SwitchToThread方法,
  • 区别在于SwitchToThread函数只会切换到当前核心逻辑关联的待运行队列的线程,不会切换到其他核心逻辑关联的线程上,而SleepEx函数会切换到任意逻辑核心关联的待运行队列中的线程,并且让当前线程在指定时间内无法重新进入待运行队列(如果线程为0 那么线程可以立刻重新进入待运行队列)
  • 在Linux和OSX中 Thread.Sleep函数在休眠时间不为0时会调用pthread类库提供的pthread_cond_timedWait函数,在休眠时间为0时会调用sched_yield函数,Thread.Yield同样会调用sched_yield函数 sched_yield在windows和osx系统中没有区别,都只会切换到当前和逻辑核心关心的待运行队列中的线程,不会切换到其他核心逻辑关联的线程上。在unix系统上调用系统提供的sleep函数并传入0 会直接忽略返回

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

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

自旋锁与互斥锁的对比手工实现自旋锁(代码片段)

...details/53695111)  本文之前,我只是对自旋锁有所了解,知道它是做什么的,但是没有去测试实现过,甚至以为自旋锁只有kernel用这个,今天才 查看详情

带你深入理解多线程---锁策略篇(代码片段)

这里写目录标题乐观锁CASCAS概念组成部分机制原理乐观锁的实现存在ABA问题举例:银行转账ABA问题代码实现解决ABA问题悲观锁共享锁/非共享锁(独占锁)读写锁概念读写锁代码实现公平锁和非公平锁概念优点java实现... 查看详情

一文带你了解anr(测试人员)(代码片段)

一、首先,了解一下什么是ANRANR,是“Application?Not?Responding”的缩写,即“应用程序无响应”。系统会向用户显示一个对话框,用户可以选择“等待”而让程序继续运行,也可以选择“强制关闭”。在Android中,应用程序的响应是... 查看详情

一文带你了解大数据技术之hadoop(代码片段)

Hadoop概述1.Hadoop是什么2.Hadoop发展历史3.Hadoop三大发行版本3.1ApacheHadoop3.2ClouderaHadoop3.3HortonworksHadoop4.Hadoop优势5.Hadoop组成5.1HDFS架构概述5.2YARN架构概述5.3MapReduce架构概述5.4HDFS、YARN、MapReduce三者关系6.大数据技术生态体系7.推荐系统... 查看详情

一文带你了解大数据技术之hadoop(yarn)(代码片段)

Yarn资源调度器1.Yarn基础架构2.Yarn工作机制3.作业提交全过程4.Yarn调度器和调度算法4.1先进先出调度器(FIFO)4.2容量调度器(CapacityScheduler)4.3公平调度器(FairScheduler)5.Yarn常用命令5.1yarnapplication查看任务5.... 查看详情

[万字长文]一文带你深入了解androidgradle(代码片段)

作为每一个Android研发,相信对gradle并不陌生,androidstudio新建每个项目或者module都会自动生成gradle文件,AS默认也是采用Gradle作为构建工具的。但是apk打包背后是如何gradle产生联系,以及gradle还能为我们平时的开发... 查看详情

一文带你了解android架构演进史(代码片段)

一.MVC架构1.概述MVC架构是第一个应用于Android开发的成熟架构,由Model、View、Controller三部分组成:Model:负责数据的存储及相关逻辑。View:负责界面展示。Controller:负责业务逻辑。MVC架构将代码逻辑分成了数... 查看详情

一文带你了解单元测试和基准测试干货(代码片段)

 在平时,通过代码实战部分你可以看到,在写每个功能的时候,都会编写测试代码。那是因为TDD(Test-DrivenDevelopment,测试驱动开发)中提倡先编写测试代码,然后再编写功能代码,每做一个修改... 查看详情

一文带你了解单元测试和基准测试干货(代码片段)

 在平时,通过代码实战部分你可以看到,在写每个功能的时候,都会编写测试代码。那是因为TDD(Test-DrivenDevelopment,测试驱动开发)中提倡先编写测试代码,然后再编写功能代码,每做一个修改... 查看详情

一文带你了解大数据技术之zookeeper(入门级)(代码片段)

大数据技术之Zookeeper入门1.Zookeeper概述2.Zookeeper特点3.数据结构4.应用场景5.下载地址1.Zookeeper概述Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。Zookeeper的工作机制:2.Zookeeper特点3.数据结构4.应用... 查看详情

一文带你了解spark架构设计与原理思想(代码片段)

        卷友们,大家好~我是Alex。之前已经陆续输出了Hadoop三大核心组件的架构思想和原理和Hive架构设计和原理,每篇都受到了读者小伙伴们的一致好评~感谢大家的支持。大家可能已经猜到了,按照发展趋势... 查看详情

一文带你了解spark架构设计与原理思想(代码片段)

        卷友们,大家好~我是Alex。之前已经陆续输出了Hadoop三大核心组件的架构思想和原理和Hive架构设计和原理,每篇都受到了读者小伙伴们的一致好评~感谢大家的支持。大家可能已经猜到了,按照发展趋势... 查看详情

一文带你了解spark架构设计与原理思想(代码片段)

        卷友们,大家好~我是Alex。之前已经陆续输出了Hadoop三大核心组件的架构思想和原理和Hive架构设计和原理,每篇都受到了读者小伙伴们的一致好评~感谢大家的支持。大家可能已经猜到了,按照发展趋势... 查看详情

一文带你了解spark架构设计与原理思想(代码片段)

        卷友们,大家好~我是Alex。之前已经陆续输出了Hadoop三大核心组件的架构思想和原理和Hive架构设计和原理,每篇都受到了读者小伙伴们的一致好评~感谢大家的支持。大家可能已经猜到了,按照发展趋势... 查看详情

猿创征文|一文带你了解前端开发者工具(代码片段)

前端开发者工具目录一、前言二、前端开发者工具——编译器(含插件)1、VSCode2、VSCode必备插件3、WebStorm三、前端开发者工具——UI框架工具1、Element2、Vant四、前端开发者工具——API调试工具1、ApiPost五、写在最后(... 查看详情

玩转css一文带你了解浮动(代码片段)

🔥一个人走得远了,就会忘记自己为了什么而出发,希望你可以不忘初心,不要随波逐流,一直走下去🎶🦋欢迎关注🖱点赞👍收藏🌟留言🐾🦄本文由程序喵正在路上原创,CS... 查看详情

熬夜之作:一文带你了解cat分布式监控(代码片段)

Cat是什么?CAT(CentralApplicationTracking)是基于Java开发的实时应用监控平台,包括实时应用监控,业务监控。CAT作为服务端项目基础组件,提供了Java,C/C++,Node.js,Python,Go等多语言客户端,已经在美团点评的基础架构中间件框架(MVC... 查看详情

一文带你了解java8之stream(代码片段)

Java8Stream流式编程简介Java8中stream是用于对集合迭代器的增强,使之能供完成更高效的聚合操作(例如过滤、排序、统计分组等)或者大批量数据操作。此外,stream与lambda表达式结合后编码效率将会大大提高,并且可以提... 查看详情