欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C# lock Monitor Mutex SpinLock 区别

程序员文章站 2022-04-19 08:22:34
...

1、Mutex 互斥锁

 Mutex mut = new Mutex();
...
mut.WaitOne();
...
mut.ReleaseMutex();//释放锁

 只能有一个线程 进入执行逻辑

if (mut.WaitOne(1000)) {     //等待一个时间,超过时间将返回false    
           // Simulate some work.
           Thread.Sleep(5000);
           // Release the Mutex.
              mut.ReleaseMutex();
        }
        else {
           Console.WriteLine("{0} will not acquire the mutex", 
                             Thread.CurrentThread.Name);
        }

 上面的实例说明,当一个线程进入执行逻辑后,如果其他线程等待超时,将不再进入执行逻辑。

2、Monitor --只能加锁 引用类型对象

Random rnd = new Random();//定义一随机数生成对象
 Monitor.Enter(rnd);
   ...
 Monitor.Exit(rnd);

 当锁定一个值类型,会出现什么情况呢?每个任务都将引发 SynchronizationLockException 异常。如下代码所示

int nTasks = 0;
Monitor.Enter(nTasks);
 try {
    nTasks += 1;
  }
finally {
       Monitor.Exit(nTasks);
}

 原因:Monitor会对nTasks进行装箱,退出的时候将不再是同一个引用对象,所以会抛出异常。

以上的解决方法是,使用nTasks之前先进行装箱。

 int nTasks = 0;
 object o = nTasks;
  Monitor.Enter(o);
try {
   nTasks++;
  }
 finally {
 Monitor.Exit(o);
 }

 3、lock 关键字--底层由Monitor实现。

lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
lock 关键字在块的开始处调用 Enter,而在块的结尾处调用 Exit。 ThreadInterruptedException 引发,如果 Interrupt 中断等待输入 lock 语句的线程。
通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。

常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:
如果实例可以被公共访问,将出现 lock (this) 问题。
如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。
由于进程中使用同一字符串的任何其他代码都将共享同一个锁,所以出现 lock("myLock") 问题。
最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。
在 lock 语句的正文不能使用 等待 关键字。

Enter指的是Monitor.Enter(获取指定对象上的排他锁。),Exit指的是Monitor.Exit(释放指定对象上的排他锁。)

所以lock底层是Monitor实现的。

private static object objlock = new object();
lock (objlock )
{
    //要执行的代码逻辑
}

 4、SpinLock 是一种低级互斥锁,可用于等待时间非常短的方案。

如果锁住的逻辑执行时间很短,请使用spinlock,这样会获得比lock 更高的性能

 

SpinLock _spinlock = new SpinLock();
...
         bool lockTaken = false;
         try
         {
             _spinlock.Enter(ref lockTaken);
             ...;//执行时间短的逻辑                
         }
         finally
         { 
             if (lockTaken) _spinlock.Exit(false);
         } 

 在 SpinLock.Exit 调用中使用 false 这可提供最佳性能。true的话会启动异常跟踪