在ac#threading应用程序中,如果我要锁定一个对象,让我们说一个队列,如果发生异常,该对象是否会保持锁定状态?这是伪代码:
int ii; lock(MyQueue) { MyClass LclClass = (MyClass)MyQueue.Dequeue(); try { ii = int.parse(LclClass.SomeString); } catch { MessageBox.Show("Error parsing string"); } }
据我所知,catch之后的代码没有执行 - 但我一直想知道锁是否会被释放.
我注意到没有人在他们对这个老问题的回答中提到释放锁定异常是一件非常危险的事情.是的,C#中的锁语句具有"最终"语义; 当控制器正常或异常退出锁定时,锁定被释放.你们都在谈论这件事,好像这是一件好事,但这是一件坏事!如果你有一个引发未处理异常的锁定区域,那么正确的做法是在它破坏更多用户数据之前立即终止病态进程,而不是释放锁定并继续运行.
这样看:假设你有一个带门锁的浴室和一排在外面等候的人.浴室里的炸弹爆炸了,杀死了那里的人.你的问题是"在那种情况下,锁会自动解锁,以便下一个人可以进入浴室吗?" 是的,它会的. 那不是一件好事.一枚炸弹刚刚在那里爆炸并杀死了一个人!管道可能被破坏,房子不再结构健全,那里可能还有另一枚炸弹.正确的做法是尽快让所有人离开并拆除整个房子.
我的意思是,通过思考:如果你锁定了一个代码区域,以便从数据结构中读取而不在另一个线程上进行变异,并且该数据结构中的某些内容引发异常,那么因为数据结构的可能性很大是腐败的.用户数据现在搞砸了; 此时您不想尝试保存用户数据,因为您正在保存损坏的数据.只需终止该过程.
如果你锁定一个代码区域以便在没有另一个线程同时读取状态的情况下执行突变,并且突变抛出,那么如果数据之前没有损坏,那么现在肯定是.这正是锁应该防范的情况.现在,等待读取该状态的代码将立即被授予访问腐败状态的权限,并且可能本身崩溃.同样,正确的做法是终止该过程.
无论你如何切片,锁内的异常都是坏消息.要问的正确问题不是"如果发生异常,我的锁会被清除吗?" 要问的正确问题是"如何确保锁定内部永远不会出现异常?如果有,那么我如何构建我的程序以使突变回滚到以前的良好状态?"
第一; 你考虑过TryParse吗?
in li; if(int.TryParse(LclClass.SomeString, out li)) { // li is now assigned } else { // input string is dodgy }
锁定将被释放有两个原因; 首先,lock
基本上是:
Monitor.Enter(lockObj); try { // ... } finally { Monitor.Exit(lockObj); }
第二; 你捕获并且不会重新抛出内部异常,所以lock
从来没有真正看到异常.当然,您在MessageBox的持续时间内持有锁,这可能是个问题.
因此它将在除了最致命的灾难性不可恢复的例外之外发布.
是的,这将正确释放; lock
充当try
/ finally
,与Monitor.Exit(myLock)
最终,所以无论你如何退出它将被释放.作为附注,catch(... e) {throw e;}
最好避免,因为这会损坏堆栈跟踪e
; 最好不要抓住它在所有的,或者:使用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
块保证你如何离开来执行,不管try
块.