【多线程笔记】自旋锁-SpinLock

自旋锁(spinlock)

是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。

什么情况下使用自旋锁

自旋锁非常有助于避免阻塞,但是如果预期有大量阻塞,由于旋转过多,您可能不应该使用自旋锁。当锁是细粒度的并且数量巨大时以及锁保持时间总是非常短时,旋转可能非常有帮助。
短时间锁定的情况下,自旋锁(spinlock)更快。(因为自旋锁本质上不会让线程休眠,而是一直循环尝试对资源访问,直到可用。所以自旋锁线程被阻塞时,不进行线程上下文切换,而是空转等待。对于多核CPU而言,减少了切换线程上下文的开销,从而提高了性能。)

SpinLock和Lock的区别

SpinLock,自旋锁。尝试获取该锁的线程持续不断的check是否可以获得。此时线程仍然是激活状态,只是在空转,浪费cpu而已。但是spinlock避免了线程调度和上下文切换,如果锁的时间极短的话,使用该锁反而效率会高。
而lock是线程被block了。这将引起线程调度和上下文切换等行为。

演示

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
  
namespace spinLock
{
    class Program
    {
        //得到当前线程的handler
        [DllImport("kernel32.dll")]
        static extern IntPtr GetCurrentThread();
        //创建自旋锁
        private static SpinLock spin = new SpinLock();
        public static void doWork1()
        {
            bool lockTaken = false;
            try
            {
                //申请获取锁
                spin.Enter(ref lockTaken);
                //下面为临界区
                for(int i=0;i<10;++i)
                {
                   Console.WriteLine(2);
                }
            }
            finally
            {
                //工作完毕,或者发生异常时,检测一下当前线程是否占有锁,如果咱有了锁释放它
                //以避免出现死锁的情况
                if (lockTaken)
                    spin.Exit();
            }
        }
        public static void doWork2()
        {
            bool lockTaken = false;
            try
            {
                spin.Enter(ref lockTaken);
                for (int i = 0; i < 10; ++i)
                {
                    Console.WriteLine(1);
                }
            }
            finally
            {
                if (lockTaken)
                    spin.Exit();
            }
  
        }
        static void Main(string[] args)
        {
            Thread[] t = new Thread[2];
            t[0] = new Thread(new ThreadStart(doWork1));
            t[1] = new Thread(new ThreadStart(doWork2));
            t[0].Start();
            t[1].Start();
            t[0].Join();
            t[1].Join();
            Console.ReadKey();
        }
    }
}
posted @ 2020-05-31 10:49  .Neterr  阅读(342)  评论(0编辑  收藏  举报