SpinLock(自旋锁)

SpinLock(自旋锁)

SpinLock 结构是一个低级别的互斥同步基元,它在等待获取锁时进行旋转。 在多核计算机上,当等待时间预计较短且极少出现争用情况时,SpinLock 的性能将高于其他类型的锁。 不过,仅在通过分析确定 System.Threading.Monitor 方法或 Interlocked 方法显著降低了程序的性能时使用 SpinLock。

System.Threading.SpinLock 是一个低级别的互斥锁,可用于等待时间非常短的场合SpinLock 不是可重入的。 在线程进入锁之后,它必须先正确地退出锁,然后才能再次进入锁。 通常,任何重新进入锁的尝试都会导致死锁,并且死锁非常难调试。 作为开发的辅助手段,System.Threading.SpinLock 支持一种线程跟踪模式,当线程尝试重新进入它已经持有的锁时,此模式将会导致引发异常。 这将让您更易于定位到锁未正确退出的点。 通过使用一个采用布尔输入形参的 SpinLock 构造函数并传入 true 实参,可以启用线程跟踪模式。 完成开发和测试阶段之后,应关闭线程跟踪模式以获得更好的性能。

使用SpinLock的Demo:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace MyConsole2
{
    class Program
    {
        const int N = 10000;
        static Queue<Data> _queue = new Queue<Data>();
        static object _lock = new object();
        static SpinLock _spinlock = new SpinLock();
        class Data
        {
            public string Name { get; set; }
            public double Number { get; set; }
        }

        static void UpdateWithSpinLock(Data d, int i)
        {
            bool lockTaken = false;
            try
            {
                _spinlock.Enter(ref lockTaken);
                _queue.Enqueue(d);
            }
            finally
            {
                if (lockTaken) _spinlock.Exit(false);
            }
             
        }

        static void UseSpinLock()
        {
            Stopwatch sw = Stopwatch.StartNew();

            Parallel.Invoke(()=> {
                for (int i = 0; i < N; i++)
                {
                    UpdateWithSpinLock(new Data() { Name = i.ToString(), Number = i }, i);
                }
            },
            ()=> {
                for (int i = 0; i < N; i++)
                {
                    UpdateWithSpinLock(new Data() { Name = i.ToString(), Number = i }, i);
                }
            });

            sw.Stop();
            Console.WriteLine("elapsed ms with spinlock: {0}", sw.ElapsedMilliseconds);

        }

        static void UpdateWithLock(Data d, int i)
        {
            lock (_lock)
            {
                _queue.Enqueue(d);
            }
        }

        private static void UseLock()
        {
            Stopwatch sw = Stopwatch.StartNew();

            Parallel.Invoke(
                    () => {
                        for (int i = 0; i < N; i++)
                        {
                            UpdateWithLock(new Data() { Name = i.ToString(), Number = i }, i);
                        }
                    },
                    () => {
                        for (int i = 0; i < N; i++)
                        {
                            UpdateWithLock(new Data() { Name = i.ToString(), Number = i }, i);
                        }
                    }
                );
            sw.Stop();
            Console.WriteLine("elapsed ms with lock: {0}", sw.ElapsedMilliseconds);
        }
        static void Main(string[] args)
        {
            UseLock();
            _queue.Clear();
            UseSpinLock();

            Console.ReadLine();
        }        

    }

}

你可能感兴趣的:(Lock)