How does lock work exactly?
我看到,对于使用非线程安全的对象,我们使用这样的锁包装代码:
1 2 3 4 5 6
| private static readonly Object obj = new Object();
lock (obj )
{
// thread unsafe code
} |
所以当多个线程访问同一代码时会发生什么(假设它在ASP.NET Web应用程序中运行)。他们在排队吗?如果是,他们会等多久?
使用锁会对性能产生什么影响?
- yoda.arachsys.com/csharp/threads/线程
lock语句由c 3.0翻译为以下内容:
1 2 3 4 5 6 7 8 9 10 11 12
| var temp = obj;
Monitor.Enter(temp);
try
{
// body
}
finally
{
Monitor.Exit(temp);
} |
在C 4.0中,这一点已经改变,现在生成如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| bool lockWasTaken = false;
var temp = obj;
try
{
Monitor.Enter(temp, ref lockWasTaken);
// body
}
finally
{
if (lockWasTaken)
{
Monitor.Exit(temp);
}
} |
你可以在这里找到更多关于Monitor.Enter所做工作的信息。引用MSDN:
Use Enter to acquire the Monitor on
the object passed as the parameter. 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. It is
legal for the same thread to invoke
Enter more than once without it
blocking; however, an equal number of
Exit calls must be invoked before
other threads waiting on the object
will unblock.
Monitor.Enter方法将无限等待,不会超时。
- 根据msdn,"使用lock(c)或synclock(Visual Basic)关键字通常比直接使用monitor类更受欢迎,这是因为lock或synclock更简洁,而且lock或synclock确保释放基础监视器,即使受保护的代码引发异常也是如此。这是通过finally关键字完成的,该关键字执行其关联的代码块,而不管是否引发异常。"msdn.microsoft.com/en-us/library/ms173179.aspx
- var temp=obj;行的意义是什么?因为这只是一个裁判开始,有什么好处使另一个呢?
- @priehl允许用户在整个系统不死锁的情况下更改obj。
- 只是另一种句法糖分?
- @乔伊蒙最终,每一种语言特征都是句法上的糖分。语言特性是关于使开发人员更有效率和使应用程序更易于维护,锁特性也是如此。
- 在某种意义上纠正@steven。我不确定每一种语言特征是否都是句法上的糖分。我们在.NET上下文中,如果有什么东西对于clr来说是未知的,并且我们在代码中使用它,那么它就是开发人员的糖。这就是我的理解。如果我错了就纠正我。如果我们从C++角度思考类是句法糖,因为机器不知道什么是类。
- 这是否意味着,如果在不同的方法中对锁使用相同的"对象",无论线程命中的方法是什么,如果有另一个线程使用锁中使用的相同"对象"执行另一个方法,则线程必须等待"对象"释放?谢谢你的时间。
- 对的。这是lock语句和监视器的全部用途:这样您就可以在一个线程中执行操作,而不必担心另一个线程会弄脏它。
比你想象的简单。
据微软称:lock关键字确保一个线程不进入代码的关键部分,而另一个线程在关键部分。如果另一个线程试图输入锁定的代码,它将等待、阻止,直到对象被释放。
lock关键字在块的开头调用Enter,在块的结尾调用Exit。lock关键字实际上处理后端的Monitor类。
例如:
1 2 3 4 5 6
| private static readonly Object obj = new Object();
lock (obj )
{
// critical section
} |
在上面的代码中,首先线程进入一个关键部分,然后它将锁定obj。当另一个线程试图进入时,它还将尝试锁定已被第一个线程锁定的obj。我必须等待第一个线程释放obj。当第一个线程离开时,另一个线程将锁定obj,并进入关键部分。
- 我们应该创建一个要锁定的虚拟对象,还是可以在上下文中锁定一个现有变量?
- @batmaci-锁定单独的私有虚拟对象可以保证没有其他人锁定该对象。如果您锁定了数据,并且同一数据块对外部可见,那么您将失去该保证。
- 如果多个进程正在等待释放锁,会发生什么情况?等待进程是否排队以便按FIFO顺序锁定关键部分?
不,他们没有排队,他们在睡觉
窗体的锁语句
其中x是引用类型的表达式,精确等于
1 2 3 4
| var temp = x;
System.Threading.Monitor.Enter(temp);
try { ... }
finally { System.Threading.Monitor.Exit(temp); } |
您只需要知道它们正在等待对方,并且只有一个线程将进入锁块,其他线程将等待…
监视器完全写在.NET中,因此足够快,还可以查看带有反射镜的类监视器以了解更多详细信息。
- 注意,在c 4:blogs.msdn.com/b/ericlippert/archive/2009/03/06/&hellip中,为lock语句发出的代码略有变化;
- @arsenmkrt,它们没有保持在"阻塞"状态队列中?我认为睡眠状态和阻塞状态之间是有区别的,不是吗?
- 你说的"莫汉维尔"是什么意思?
- 如果多个进程正在等待释放锁,会发生什么情况?等待进程是否排队以便按FIFO顺序锁定关键部分?
- @jstuardo、lock或monitor在进程外不可见…它只对单个进程中的线程有意义…对于进程互斥,可以使用信号量或其他Windows核心对象…
- 这不是问题。问题是关于"lock"关键字。假设一个进程进入一个"锁"部分。这意味着进程会阻塞这段代码,在释放锁之前,其他进程可能无法进入该部分。好。。。。现在,还有两个进程试图进入同一个块。因为它是由"锁"关键字保护的,他们会等待,根据本论坛所说的。当第一个进程释放锁时。哪个进程进入该块?第一个尝试进入还是最后一个?
- 我猜你的意思是线程而不是进程…如果是这样,那么答案是否定的,就不能保证谁会进入……更多信息请访问stackoverflow.com/questions/4228864/…
- 谢谢。。。。。实际上我指的是线。
锁将阻止其他线程执行锁块中包含的代码。线程必须等待锁块内的线程完成并释放锁。这确实会对多线程环境中的性能产生负面影响。如果您确实需要这样做,您应该确保锁块中的代码可以很快地处理。您应该尽量避免昂贵的活动,如访问数据库等。
性能影响取决于锁定的方式。你可以在这里找到一个很好的优化列表:http://www.thinkingparallel.com/2007/07/31/10-ways-to-reduce-lock-competition-in-threaded-programs/
基本上,你应该尽量少锁,因为它会让你的等待代码进入睡眠状态。如果在锁中有一些繁重的计算或持久的代码(例如文件上传),则会导致巨大的性能损失。
- 但是尝试编写低锁代码通常会导致细微的、难以发现和修复的错误,即使您是该领域的专家。使用锁通常是两种邪恶中较小的一种。你应该尽可能多地锁,不多不少!
- @Lukeh:有一些使用模式,低锁代码可以非常简单和容易[do { oldValue = thing; newValue = updated(oldValue); } while (CompareExchange(ref thing, newValue, oldValue) != oldValue]。最大的危险是,如果需求的发展超出了这些技术可以处理的范围,那么很难调整代码来处理这些问题。
- 链接已断开。
lock语句转换为对Monitor的Enter和Exit方法的调用。
lock语句将无限期地等待释放锁定对象。
lock语句中的部分只能由一个线程执行,因此所有其他线程都将无限期地等待该部分完成:持有锁的线程。这会导致所谓的死锁。
锁实际上是隐藏的监视器类。