locking的对象是否locking,如果内部发生exception?
在ac#线程应用程序,如果我要locking一个对象,让我们说一个队列,如果发生exception,对象将保持locking? 这里是伪代码:
int ii; lock(MyQueue) { MyClass LclClass = (MyClass)MyQueue.Dequeue(); try { ii = int.parse(LclClass.SomeString); } catch { MessageBox.Show("Error parsing string"); } }
据我了解,catch之后的代码不会执行 – 但我一直在想如果锁将被释放。
第一; 你有没有考虑过TryParse?
in li; if(int.TryParse(LclClass.SomeString, out li)) { // li is now assigned } else { // input string is dodgy }
locking将被释放有两个原因。 首先, lock
本质上是:
Monitor.Enter(lockObj); try { // ... } finally { Monitor.Exit(lockObj); }
第二; 你捕获并不重新抛出内部exception,所以lock
实际上从来没有看到一个exception。 当然,你在MessageBox的持续时间里持有这个锁,这可能是一个问题。
所以它将被释放,除了最致命的灾难性的不可恢复的例外。
我注意到,在这个老问题的答案中没有人提到, 解除例外情况是一件非常危险的事情。 是的,C#中的locking语句具有“finally”语义; 当控制正常或exception退出locking时,locking被释放。 你们都在说这是好事,但这是一件坏事! 如果你有一个locking的区域引发一个未处理的exception,那么正确的做法是在它破坏更多的用户数据之前立即终止病态进程 ,而不是释放锁并继续进行 。
这样看:假设你有一间带门锁的浴室,还有一排在外面等着的人。 浴室里的一枚炸弹熄灭,炸死了那里的人。 你的问题是“在这种情况下锁会自动解锁,所以下一个人可以进入浴室吗? 是的,它会。 这不是一件好事。 一颗炸弹刚刚在那里爆炸,杀死了一个人! pipe道很可能被毁坏了,房子不再结构化了, 那里可能还有另外一个炸弹 。 正确的做法是尽快将所有人赶出去,拆除整个房子。
我的意思是,想一想:如果你locking了一段代码,以便从一个数据结构中读取而不会在另一个线程上发生变化,并且该数据结构中的某个东西会抛出一个exception,那么可能性很大,因为数据结构是腐败的 。 用户数据现在混乱了; 您不希望尝试在此时保存用户数据 ,因为您正在保存损坏的数据。 只要终止这个过程。
如果你locking了一段代码,以便在没有另一个线程同时读取状态的情况下执行变化,并且突变抛出,那么如果数据之前没有被破坏,现在肯定是这样 。 这正是锁应该防止的情况 。 现在正在等待读取状态的代码将立即被授予访问损坏状态,并可能本身崩溃。 同样,正确的做法是终止这个过程。
无论你如何分片,锁内的exception都是坏消息 。 要问的正确的问题不是“如果发生exception,我的锁会被清理干净吗? 要问的正确的问题是“我如何确保锁内永远不会有exception?如果存在,那么我该如何构造我的程序,使突变回到先前的好状态?
是的,这将正确地释放; lock
作为try
/ finally
,随着Monitor.Exit(myLock)
在最后,所以不pipe你如何退出它将被释放。 作为一个侧面说明,最好避免catch(... e) {throw e;}
,因为这会损坏e
上的堆栈跟踪; 最好不要抓到它,或者select:使用throw;
而不是throw e;
这是一个重新抛出。
如果你真的想知道,C#4 / .NET 4中的锁是:
{ bool haveLock = false; try { Monitor.Enter(myLock, ref haveLock); } finally { if(haveLock) Monitor.Exit(myLock); } }
“锁语句被编译为对Monitor.Enter的调用,然后try … finally块。在finally块中,Monitor.Exit被调用。
x86和x64的JIT代码生成确保了在一个Monitor.Enter调用和一个紧跟它后面的try块之间不会发生线程中止。
采取: 这个网站
你的锁将被正确释放。 lock
是这样的:
try { Monitor.Enter(myLock); // ... } finally { Monitor.Exit(myLock); }
finally
块保证执行,不pipe你如何离开try
块。
只要给Marc的优秀答案补充一点。
像这样的情况是lock
关键字存在的原因。 它可以帮助开发者确保锁在finally
块中被释放。
如果您不得不使用Monitor.Enter
/ Exit
例如支持超时),则必须确保将调用放置在finally
块中的Monitor.Exit
中,以确保在出现exception时正确释放锁。