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时正确释放锁。