我的编程空间,编程开发者的网络收藏夹
学习永远不晚

.Net基于Thread实现自旋锁的三种方式

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

.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基于Thread实现自旋锁的三种方式的详细内容,更多关于.Net自旋锁的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

.Net基于Thread实现自旋锁的三种方式

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java实现redis分布式锁的三种方式

本文主要介绍了Java实现redis分布式锁的三种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2022-11-13

php实现递归的三种基本方式

在PHP中,有三种基本方式可以实现递归:1. 使用函数自身的方式:```phpfunction recursion($n) {if ($n return;}echo $n . " ";recursion($n - 1);}recursion
2023-08-09

Android自定义View的三种实现方式总结

在毕设项目中多处用到自定义控件,一直打算总结一下自定义控件的实现方式,今天就来总结一下吧。在此之前学习了郭霖大神博客上面关于自定义View的几篇博文,感觉受益良多,本文中就参考了其中的一些内容。 总结来说,自定义控件的实现有三种方式,分别是
2022-06-06

koa2实现session的两种方式(基于Redis 和MySQL)

一.基于MySQL的实现方式这种方式需要安装koa-session-minimal和koa-mysql-session两个依赖。执行npm install koa-session-minimal koa-mysql-session项目配置:const sess
koa2实现session的两种方式(基于Redis 和MySQL)
2014-08-19

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录