我看到,对于使用非线程安全的对象,我们用这样的锁包装代码:

private static readonly Object obj = new Object();

lock (obj)
{
    // thread unsafe code
}

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

使用锁对性能有什么影响?


当前回答

lock语句被转换为对Monitor的Enter和Exit方法的调用。

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

其他回答

lock实际上是隐藏的Monitor类。

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 对象,但尚未执行 相应的退出,电流 线程将阻塞直到另一个 线程释放对象。它是 同一线程调用是合法的 不带它进入不止一次 阻塞;然而,同样数量的 之前必须调用退出调用 等待该对象的其他线程 将开启。

监视器。进入方法将无限等待;它不会超时。

根据微软的MSDN,这个锁相当于:

object __lockObj = x;
bool __lockWasTaken = false;
try
{
    System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
    // Your code...
}
finally
{
    if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
}

如果需要在运行时创建锁,可以使用开源的DynaLock。您可以在运行时创建新锁,并使用上下文概念指定锁的边界。

DynaLock是开源的,源代码可以在GitHub上获得

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

表单的锁语句

lock (x) ... 

其中x是引用类型的表达式,精确地等价于

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

你只需要知道它们在等待彼此,只有一个线程会进入锁块,其他线程会等待…

Monitor是完全用。net编写的,所以足够快,还可以查看带有reflector的Monitor类了解更多细节

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