锁如何工作?

我看到,为了使用不是线程安全的对象,我们用这样的一个锁来包装代码:

private static readonly Object obj = new Object(); lock (obj) { // thread unsafe code } 

那么当多个线程访问相同的代码时会发生什么(让我们假设它正在ASP.NET Web应用程序中运行)。 他们排队吗? 如果是的话,他们会等多久?

由于使用锁,对性能的影响是什么?

lock语句由C#3.0翻译为以下内容:

 var temp = obj; Monitor.Enter(temp); try { // body } finally { Monitor.Exit(temp); } 

在C#4.0中, 这已经改变 ,现在生成如下:

 bool lockWasTaken = false; var temp = obj; try { Monitor.Enter(temp, ref lockWasTaken); // body } finally { if (lockWasTaken) { Monitor.Exit(temp); } } 

你可以在这里find关于Monitor.Enter更多信息。 引用MSDN:

使用Enter获取作为parameter passing的对象上的监视器。 如果另一个线程在对象上执行了一个Enter但尚未执行相应的Exit ,则当前线程将被阻塞,直到另一个线程释放该对象。 同一个线程在不阻塞的情况下多次调用Enter是合法的; 但是,等待对象的其他线程将被解除阻塞之前,必须调用相同数量的Exit调用。

Monitor.Enter方法将无限等待; 它不会超时。

它比你想象的更简单。

根据微软 : lock关键字确保一个线程不进入关键部分的代码,而另一个线程是关键部分。 如果另一个线程试图input一个locking的代码,它将等待,阻止,直到对象被释放。

lock关键字在块的开始处调用Enter ,在块的结尾处调用Exitlock关键字实际上处理后端的Monitor类。

例如:

 private static readonly Object obj = new Object(); lock (obj) { // critical section } 

在上面的代码中,第一个线程进入关键部分,然后lockingobj ,当其他线程尝试进入时,它也会尝试locking已经被第一个线程locking的obj ,我将不得不等待第一个线程释放obj 。 当第一个将离开时,其他线程将lockingobj ,并将进入关键部分。

不,他们没有排队,他们在睡觉

表单的locking语句

 lock (x) ... 

其中x是一个引用types的expression式,恰恰相当于

 var temp = x; System.Threading.Monitor.Enter(temp); try { ... } finally { System.Threading.Monitor.Exit(temp); } 

你只需要知道他们正在等待对方,只有一个线程将进入locking块,其他人将等待…

监视器是完全写在.net所以它是足够快,也看类 reflection器 监视器更多的细节

锁将阻止其他线程执行锁块中包含的代码。 线程将不得不等待锁块内的线程完成并释放锁。 这对multithreading环境中的性能有负面影响。 如果你确实需要这样做,你应该确保锁块内的代码可以很快处理。 你应该尽量避免昂贵的活动,如访问数据库等

性能影响取决于您locking的方式。 你可以在这里find一个优化列表: http : //www.thinkingparallel.com/2007/07/31/10-ways-to-reduce-lock-contention-in-threaded-programs/

基本上你应该尝试尽可能less的locking,因为它会让你等待的代码进入hibernate状态。 如果你有一些繁重的计算或长时间的代码(例如file upload)在一个锁中,会导致巨大的性能损失。

lock语句中的部分只能由一个线程执行,所有其他线程将无限期地等待持有该锁的线程完成。 这可能导致所谓的死锁。

lock语句被转换为对MonitorEnterExit方法的调用。

lock语句将无限期地等待locking对象被释放。

锁实际上是隐藏的监视器类。