简体   繁体   English

lock 语句在底层做了什么?

[英]What does a lock statement do under the hood?

I see that for using objects which are not thread safe we wrap the code with a lock like this:我看到为了使用非线程安全的对象,我们用这样的锁包装代码:

private static readonly Object obj = new Object();

lock (obj)
{
    // thread unsafe code
}

So, what happens when multiple threads access the same code (let's assume that it is running in a ASP.NET web application).那么,当多个线程访问相同的代码时会发生什么(假设它在 ASP.NET Web 应用程序中运行)。 Are they queued?他们排队吗? If so how long will they wait?如果是这样,他们要等多久?

What is the performance impact because of using locks?使用锁对性能有什么影响?

The lock statement is translated by C# 3.0 to the following: lock语句由 C# 3.0 转换为以下内容:

var temp = obj;

Monitor.Enter(temp);

try
{
    // body
}
finally
{
    Monitor.Exit(temp);
}

In C# 4.0 this has changed and it is now generated as follows:在 C# 4.0 中, 这已更改,现在生成如下:

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

You can find more info about what Monitor.Enter does here .您可以在此处找到有关Monitor.Enter功能的更多信息。 To quote MSDN:引用 MSDN:

Use Enter to acquire the Monitor on the object passed as the parameter.使用Enter获取作为参数传递的对象上的 Monitor。 If another thread has executed an Enter on the object but has not yet executed the corresponding Exit , the current thread will block until the other thread releases the object.如果另一个线程对对象执行了Enter但还没有执行相应的Exit ,则当前线程将阻塞,直到另一个线程释放该对象。 It is legal for the same thread to invoke Enter more than once without it blocking;同一个线程多次调用Enter而不阻塞是合法的; however, an equal number of Exit calls must be invoked before other threads waiting on the object will unblock.然而,在等待该对象的其他线程解除阻塞之前,必须调用相同数量的Exit调用。

The Monitor.Enter method will wait infinitely; Monitor.Enter方法将无限等待; it will not time out.不会超时。

Its simpler than you think-它比你想象的要简单——

According to Microsoft : The lock keyword ensures that one thread does not enter a critical section of code while another thread is in the critical section.根据微软的说法: lock关键字确保一个线程不会进入代码的临界区,而另一个线程处于临界区。 If another thread tries to enter a locked code, it will wait, block, until the object is released.如果另一个线程试图输入一个锁定的代码,它将等待、阻塞,直到对象被释放。

The lock keyword calls Enter at the start of the block and Exit at the end of the block. lock关键字在块的开头调用Enter ,在块的结尾调用Exit lock keyword actually handles Monitor class at back end. lock关键字实际上在后端处理Monitor类。

For example:例如:

private static readonly Object obj = new Object();

lock (obj)
{
    // critical section
}

In the above code, first the thread enters a critical section, and then it will lock obj .在上面的代码中,线程首先进入临界区,然后它会锁定obj When another thread tries to enter, it will also try to lock obj , which is already locked by the first thread.当另一个线程尝试进入时,它也会尝试锁定obj ,该obj已经被第一个线程锁定。 Second thread will have to wait for the first thread to release obj .第二个线程必须等待第一个线程释放obj When the first thread leaves, then another thread will lock obj and will enter the critical section.当第一个线程离开时,另一个线程将锁定obj并进入临界区。

No, they are not queued, they are sleeping不,他们没有排队,他们在睡觉

A lock statement of the form形式的锁定语句

lock (x) ... 

where x is an expression of a reference-type, is precisely equivalent to其中 x 是一个引用类型的表达式,正好等价于

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

You just need to know that they are waiting to each other, and only one thread will enter to lock block, the others will wait...你只需要知道它们在互相等待,只有一个线程会进入锁块,其他线程会等待......

Monitor is written fully in .net so it is enough fast, also look at class Monitor with reflector for more details Monitor 完全用 .net 编写,因此速度足够快,有关更多详细信息,还可以查看带有反射器的类 Monitor

Locks will block other threads from executing the code contained in the lock block.锁将阻止其他线程执行锁块中包含的代码。 The threads will have to wait until the thread inside the lock block has completed and the lock is released.线程必须等到锁块内的线程完成并释放锁。 This does have a negative impact on performance in a multithreaded environment.这确实对多线程环境中的性能产生负面影响。 If you do need to do this you should make sure the code within the lock block can process very quickly.如果您确实需要这样做,您应该确保锁定块中的代码可以非常快速地处理。 You should try to avoid expensive activities like accessing a database etc.您应该尽量避免昂贵的活动,例如访问数据库等。

The performance impact depends on the way you lock.性能影响取决于您锁定的方式。 You can find a good list of optimizations here: http://www.thinkingparallel.com/2007/07/31/10-ways-to-reduce-lock-contention-in-threaded-programs/你可以在这里找到一个很好的优化列表: http : //www.thinkingparallel.com/2007/07/31/10-ways-to-reduce-lock-contention-in-threaded-programs/

Basically you should try to lock as little as possible, since it puts your waiting code to sleep.基本上你应该尽量少锁定,因为它会让你的等待代码进入睡眠状态。 If you have some heavy calculations or long lasting code (eg file upload) in a lock it results in a huge performance loss.如果你在一个锁中有一些繁重的计算或持久的代码(例如文件上传),它会导致巨大的性能损失。

The part within the lock statement can only be executed by one thread, so all other threads will wait indefinitely for it the thread holding the lock to finish. lock 语句中的部分只能由一个线程执行,因此所有其他线程将无限期地等待持有锁的线程完成。 This can result in a so-called deadlock.这会导致所谓的死锁。

The lock statement is translated to calls to the Enter and Exit methods of Monitor . lock语句被转换为对MonitorEnterExit方法的调用。

The lock statement will wait indefinitely for the locking object to be released. lock语句将无限期地等待锁定对象被释放。

lock实际上是隐藏的Monitor类。

According to Microsoft's MSDN , the lock is equivalent to:根据微软的 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);
}

If you need to create locks in runtime, you can use open source DynaLock .如果您需要在运行时创建锁,您可以使用开源DynaLock You can create new locks in run-time and specify boundaries to the locks with context concept.您可以在运行时创建新锁并使用上下文概念指定锁的边界。

DynaLock is open-source and source code is available at GitHub DynaLock 是开源的,源代码可在GitHub 上获得

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM