Linux内核多线程中的-自旋锁

基础

内核锁:基于内核对象构造的锁机制,就是通常说的内核构造模式。

优点:cpu利用最大化。它发现资源被锁住,请求就排队等候。线程切换到别处干活,直到接受到可用信号,线程再切回来继续处理请求。

缺点:托管代码->用户模式代码->内核代码损耗、线程上下文切换损耗。

在锁的时间比较短时,系统频繁忙于休眠、切换,是个很大的性能损耗。

自旋锁:原子操作+自循环。通常说的用户构造模式。 线程不休眠,一直循环尝试对资源访问,直到可用。

优点:完美解决内核锁的缺点。

缺点:长时间一直循环会导致cpu的白白浪费,高并发竞争下、CPU的消耗特别严重。

混合锁:内核锁+自旋锁。 混合锁是先自旋锁一段时间或自旋多少次,再转成内核锁。

优点:内核锁和自旋锁的折中方案,利用前二者优点,避免出现极端情况(自旋时间过长,内核锁时间过短)。

缺点: 自旋多少时间、自旋多少次,这些策略很难把控。

在操作系统及net框架层,这块算法策略做的已经非常优了,有些API函数也提供了时间及次数可配置项,让使用者根据需求自行判断。

自旋锁示例

来看下我们自己简单实现的自旋锁:

        int signal = 0;
            var li = new List<int>();
            Parallel.For(0, 1000 * 10000, r =>
            {
                while (Interlocked.Exchange(ref signal, 1) != 0)//加自旋锁
                {
                    //黑魔法
                }
                li.Add(r);
                Interlocked.Exchange(ref signal, 0);  //释放锁
            });
            Console.WriteLine(li.Count);
            //输出:10000000

上面就是自旋锁:Interlocked.Exchange+while

1:定义signal 0可用,1不可用。

2:Parallel模拟并发竞争,原子更改signal状态。 后续线程自旋访问signal,是否可用。

3:A线程使用完后,更改signal为0。 剩余线程竞争访问资源,B线程胜利后,更改signal为1,失败线程继续自旋,直到可用。

SpinLock

SpinLock是net4.0后Net提供的自旋锁类库,内部做了优化。

简单看下实例:

  var li = new List<int>();
            var sl = new SpinLock();
            Parallel.For(0, 1000 * 10000, r =>
            {
                bool gotLock = false;     //释放成功
                sl.Enter(ref gotLock);    //进入锁
                li.Add(r);
                if (gotLock) sl.Exit();  //释放
            });
            Console.WriteLine(li.Count);
            //输出:10000000

继续SpinLock

new SpinLock(false) 这个构造函数主要用来检查死锁用,true是开启。

在开启状态下,一旦发生死锁会直接抛异常的。

SpinLock实现的部分源码:

  public void Enter(ref bool lockTaken) 
        {
            if (lockTaken) 
            { 
                lockTaken = false;
                throw new System.ArgumentException(Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException")); 
            }

            // Fast path to acquire the lock if the lock is released
            // If the thread tracking enabled set the new owner to the current thread id 
            // Id not, set the anonymous bit lock
            int observedOwner = m_owner; 
            int newOwner = 0; 
            bool threadTrackingEnabled = (m_owner & LOCK_ID_DISABLE_MASK) == 0;
            if (threadTrackingEnabled) 
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值