我看到,对于使用非线程安全的对象,我们用这样的锁包装代码:
private static readonly Object obj = new Object();
lock (obj)
{
// thread unsafe code
}
那么,当多个线程访问相同的代码时会发生什么(让我们假设它运行在一个ASP。NET web应用程序)。他们排队了吗?如果是的话,他们要等多久?
使用锁对性能有什么影响?
我看到,对于使用非线程安全的对象,我们用这样的锁包装代码:
private static readonly Object obj = new Object();
lock (obj)
{
// thread unsafe code
}
那么,当多个线程访问相同的代码时会发生什么(让我们假设它运行在一个ASP。NET web应用程序)。他们排队了吗?如果是的话,他们要等多久?
使用锁对性能有什么影响?
当前回答
不,他们没有排队,他们在睡觉
表单的锁语句
lock (x) ...
其中x是引用类型的表达式,精确地等价于
var temp = x;
System.Threading.Monitor.Enter(temp);
try { ... }
finally { System.Threading.Monitor.Exit(temp); }
你只需要知道它们在等待彼此,只有一个线程会进入锁块,其他线程会等待…
Monitor是完全用。net编写的,所以足够快,还可以查看带有reflector的Monitor类了解更多细节
其他回答
不,他们没有排队,他们在睡觉
表单的锁语句
lock (x) ...
其中x是引用类型的表达式,精确地等价于
var temp = x;
System.Threading.Monitor.Enter(temp);
try { ... }
finally { System.Threading.Monitor.Exit(temp); }
你只需要知道它们在等待彼此,只有一个线程会进入锁块,其他线程会等待…
Monitor是完全用。net编写的,所以足够快,还可以查看带有reflector的Monitor类了解更多细节
这比你想的要简单
微软表示: lock关键字确保当另一个线程处于临界区时,一个线程不会进入临界区。如果另一个线程试图输入一个锁定的代码,它将等待,阻塞,直到对象被释放。
lock关键字在块的开始调用Enter,在块的结束调用Exit。lock关键字实际上在后端处理Monitor类。
例如:
private static readonly Object obj = new Object();
lock (obj)
{
// critical section
}
在上面的代码中,首先线程进入临界区,然后它将锁定obj。当另一个线程试图进入时,它也会尝试锁定obj,它已经被第一个线程锁定了。第二个线程将不得不等待第一个线程释放obj。当第一个线程离开时,另一个线程将锁定obj并进入临界区。
对性能的影响取决于锁定的方式。你可以在这里找到一个很好的优化列表:http://www.thinkingparallel.com/2007/07/31/10-ways-to-reduce-lock-contention-in-threaded-programs/
基本上,您应该尽可能少地尝试锁定,因为它会使等待代码进入睡眠状态。如果你在一个锁中有一些繁重的计算或长时间的代码(例如文件上传),它会导致巨大的性能损失。
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);
}
}
你可以找到更多关于Monitor的信息。在这里输入。引用MSDN:
使用Enter键获取Monitor on 作为参数传递的对象。如果 另一个线程执行了一个Enter 对象,但尚未执行 相应的退出,电流 线程将阻塞直到另一个 线程释放对象。它是 同一线程调用是合法的 不带它进入不止一次 阻塞;然而,同样数量的 之前必须调用退出调用 等待该对象的其他线程 将开启。
监视器。进入方法将无限等待;它不会超时。
lock实际上是隐藏的Monitor类。