/// <summary>
  /// 无锁算法,如果多次冲突,这个算法不一定会比线程锁快
  /// </summary>
  public class DualCounter
  {
      public int A { get; set; }
      public int B { get; set; }

      public DualCounter(int a, int b)
      {
          A = a;
          B = b;
      }

      public static DualCounter Increment(ref DualCounter counter)
      {
          DualCounter oldValue, newValue;
          int i = 0;
          do
          {
              oldValue = counter;
              newValue = new DualCounter(oldValue.A + 1, oldValue.B + 1);
              if(0!=i++)Console.WriteLine("线程冲突,重新赋值");
              //如果conter 和 oldvalue相等则newValue替换counter,然后返回counter的值
          } while (Interlocked.CompareExchange(ref counter, newValue, oldValue) != oldValue);

          return newValue;
      }
  }


  /// <summary>
  /// 自旋锁,执行的保护区代码一定要非常快,要不然吃性能
  /// 如果获取锁失败,调用 Thread.Yield(); 来通知系统,释放锁
  /// </summary>
  public class MySpinlock
  {
      static int _lock = 0;
      // volatile static int _lock = 0;
      static int _counterA = 0;
      static int _counterB = 0;
      static SpinLock _locks = new SpinLock();
      public static void Exchange(ref int aocunter,int mnum)
      {
          bool lockTaken = false;
          try
          {
              //获取锁
              _locks.Enter(ref lockTaken);
              //保护区开始
              aocunter = mnum;
              //解除保护
          }
          finally
          {
              //如果成功获取锁则释放
              if (lockTaken)
              {
                  _locks.Exit();
              }
          }
      }

      public static void IncrementCounters()
      {
          //改变_lock 的值为1 
          var spinWait = new SpinWait();
          while(Interlocked.Exchange(ref _lock, 1) != 0)
          {
             //Thread.SpinWait(1);
              spinWait.SpinOnce(); //如果单核心则使用sleep(0) 等待,反之使用轮询 SpinWait
          }
          //线程保护区域开始
          ++_counterA;
          ++_counterB;
          //线程保护区域结束
          Interlocked.Exchange(ref _lock, 0);
      }

      public static void GetCounters(out int A,out int B)
      {
          
          //改变_lock 的值为1 
          while (Interlocked.Exchange(ref _lock, 1) != 0)//Exchange使用了内存屏障,确保cpu能够观测到
              //如果不使用Exchange可以使用 Interlocked.MemoryBarrier(内存屏障) 函数且_lock 加volatile 修饰来达到同样的效果
          {
              Thread.SpinWait(1);//自旋中,cpu根据自身特性,休息一定时钟周期,在x86架构的cpu中会使用pause汇编指令
          }
          //线程保护区域开始
          A=_counterA++;
          B=_counterB++;
          //线程保护区域结束
          
          //释放锁
          Interlocked.Exchange(ref _lock, 0);
      }
  }

  //互斥锁
   public class MyMutex
  {
      static Mutex _lock = new Mutex(false, "Local\\test");//可以重复进入锁,但是锁会进行累积,但释放到0时才是真的释放锁
      //Mutex  支持跨进程锁定,第二个参数传入"Local\"表示用一用户进程共享,"Global\"表示同一计算机进程共享,Global\test
      // 如果进程获取了锁,另外一个进程获取同一个名称的锁需要等待,如果到退出都没释放,操作系统自行释放锁
      static int _counterA = 0;
      static int _counterB = 0;
      public static void IncrementCounters()
      {
          //获取锁
          _lock.WaitOne();
          try
          {
              ++_counterA;
              ++_counterB;
          }
          finally
          {
              //释放锁
              _lock.ReleaseMutex();
          }
      }
  }

  //混合锁
  public class MyMonitor
  {
      public MyMonitor()
      {

      }
      static object _lock = new object();
      static int _countA = 0;
      public static void IncrementCounters()
      {
          object lockObj = _lock;
          bool lockTaken = false;
          try
          {
              Monitor.Enter(lockObj, ref lockTaken);
              ++_countA;
          }
          finally
          {
              if (lockTaken)
                  Monitor.Exit(lockObj);
          }
      }

      public static void IncrementCounter()
      {
          lock (_lock)//混合锁的简单写法
          {
              ++_countA;
          }
      }

      // private static Semaphore _sema = new Semaphore(0,2,"Local\\test");//信号量,最小0,最大2,跨进程
      //private static Semaphore _sema = new Semaphore(0,2);//信号量,最小0,最大2,跨进程
      private static SemaphoreSlim _sema = new SemaphoreSlim(0, 2);//轻信号量,如果不用跨进程,则优先使用它

      public static void Worker(object o)
      {
          while (true)
          {
              Console.WriteLine("线程" + o);
              //减少信号量
              //_sema.WaitOne();
              _sema.Wait();
              Console.WriteLine("wait One "+o);
          }
      }
      public static void DoWorker()
      {
          for(var x = 0; x < 6; ++x)
          {
              var thread = new Thread(new ParameterizedThreadStart(Worker));
              thread.IsBackground = true;
              thread.Start(x);
          }

          while (true)
          {
              ///添加两个信号量
              _sema.Release(1);
              Thread.Sleep(1000);
          }
      }
  }

posted on 2021-11-09 10:39  好怀念啊  阅读(39)  评论(0编辑  收藏  举报