实用技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > ASP.NET > 实用技巧 > .Net自旋锁

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

作者:初夏的阳光丶

本文主要讲解.Net基于Thread实现自旋锁的三种方式,基于Test--And--Set原子操作实现,包含优缺点介绍,感兴趣的朋友跟随小编一起看看吧


基于Thread.SpinWait实现自旋锁

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

优点:

缺点:

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

代码实现:

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中的两个问题

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的区别

以上就是.Net基于Thread实现自旋锁的三种方式的详细内容,更多关于.Net自旋锁的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文