C# 如果内部发生异常,锁定的对象是否保持锁定状态?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/590159/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Does a locked object stay locked if an exception occurs inside it?
提问by Khadaji
In a c# threading app, if I were to lock an object, let us say a queue, and if an exception occurs, will the object stay locked? Here is the pseudo-code:
在 ac# 线程应用程序中,如果我要锁定一个对象,比如说一个队列,如果发生异常,该对象会保持锁定状态吗?这是伪代码:
int ii;
lock(MyQueue)
{
MyClass LclClass = (MyClass)MyQueue.Dequeue();
try
{
ii = int.parse(LclClass.SomeString);
}
catch
{
MessageBox.Show("Error parsing string");
}
}
As I understand it, code after the catch doesn't execute - but I have been wondering if the lock will be freed.
据我了解,捕获后的代码不会执行 - 但我一直想知道锁是否会被释放。
采纳答案by Marc Gravell
First; have you considered TryParse?
第一的; 你考虑过 TryParse 吗?
in li;
if(int.TryParse(LclClass.SomeString, out li)) {
// li is now assigned
} else {
// input string is dodgy
}
The lock will be released for 2 reasons; first, lock
is essentially:
锁会因为两个原因被释放;首先,lock
本质上是:
Monitor.Enter(lockObj);
try {
// ...
} finally {
Monitor.Exit(lockObj);
}
Second; you catch and don't re-throw the inner exception, so the lock
never actually sees an exception. Of course, you are holding the lock for the duration of a MessageBox, which might be a problem.
第二; 您捕获并且不重新抛出内部异常,因此lock
从未真正看到异常。当然,您在 MessageBox 期间持有锁,这可能是一个问题。
So it will be released in all but the most fatal catastrophic unrecoverable exceptions.
因此它将在除最致命的灾难性不可恢复异常之外的所有情况下释放。
回答by Brian Rasmussen
Just to add a little to Marc's excellent answer.
只是为 Marc 的出色答案添加一点。
Situations like this are the very reason for the existence of the lock
keyword. It helps developers make sure the lock is released in the finally
block.
像这样的情况正是lock
关键字存在的原因。它可以帮助开发人员确保在finally
块中释放锁。
If you're forced to use Monitor.Enter
/Exit
e.g. to support a timeout, you must make sure to place the call to Monitor.Exit
in the finally
block to ensure proper release of the lock in case of an exception.
如果您被迫使用Monitor.Enter
/ Exit
eg 来支持超时,您必须确保将调用Monitor.Exit
放在finally
块中以确保在发生异常时正确释放锁。
回答by GH.
"A lock statement is compiled to a call to Monitor.Enter, and then a try…finally block. In the finally block, Monitor.Exit is called.
“锁定语句被编译为对 Monitor.Enter 的调用,然后是 try...finally 块。在 finally 块中,Monitor.Exit 被调用。
The JIT code generation for both x86 and x64 ensures that a thread abort cannot occur between a Monitor.Enter call and a try block that immediately follows it."
x86 和 x64 的 JIT 代码生成确保在 Monitor.Enter 调用和紧随其后的 try 块之间不会发生线程中止。”
Taken from: This site
摘自: 本站
回答by Marc Gravell
yes, that will release properly; lock
acts as try
/finally
, with the Monitor.Exit(myLock)
in the finally, so no matter how you exit it will be released. As a side-note, catch(... e) {throw e;}
is best avoided, as that damages the stack-trace on e
; it is better not to catch it at all, or alternatively: use throw;
rather than throw e;
which does a re-throw.
是的,这将正确释放;lock
充当try
/ finally
,Monitor.Exit(myLock)
在 finally 中,所以无论你如何退出它都会被释放。作为旁注,catch(... e) {throw e;}
最好避免,因为这会损坏e
; 最好不要抓住它在所有的,或者:使用throw;
而不是throw e;
它做了再扔。
If you really want to know, a lock in C#4 / .NET 4 is:
如果您真的想知道,C#4 / .NET 4 中的锁是:
{
bool haveLock = false;
try {
Monitor.Enter(myLock, ref haveLock);
} finally {
if(haveLock) Monitor.Exit(myLock);
}
}
回答by Ry-
Your lock will be released properly. A lock
acts like this:
您的锁将被正确释放。A 的lock
行为是这样的:
try {
Monitor.Enter(myLock);
// ...
} finally {
Monitor.Exit(myLock);
}
And finally
blocks are guaranteed to execute, no matter how you leave the try
block.
和finally
块保证你如何离开来执行,不管try
块。
回答by Eric Lippert
I note that no one has mentioned in their answers to this old question that releasing a lock upon an exception is an incredibly dangerous thing to do.Yes, lock statements in C# have "finally" semantics; when control exits the lock normally or abnormally, the lock is released. You're all talking about this like it is a good thing, but it is a bad thing! The right thing to do if you have a locked region that throws an unhandled exception is to terminate the diseased process immediately before it destroys more user data, not free the lock and keep on going.
我注意到没有人在他们对这个老问题的回答中提到释放对异常的锁是一件非常危险的事情。是的,C# 中的 lock 语句具有“finally”语义;当控制正常或异常退出锁时,锁被释放。你们都在说这是一件好事,但这是一件坏事!如果您有一个引发未处理异常的锁定区域,那么正确的做法是在有问题的进程破坏更多用户数据之前立即终止它,而不是释放锁定并继续运行。
Look at it this way: suppose you have a bathroom with a lock on the door and a line of people waiting outside. A bomb in the bathroom goes off, killing the person in there. Your question is "in that situation will the lock be automatically unlocked so the next person can get into the bathroom?" Yes, it will. That is not a good thing.A bomb just went off in there and killed someone! The plumbing is probably destroyed, the house is no longer structurally sound, and there might be another bomb in there. The right thing to do is get everyone out as quickly as possible and demolish the entire house.
这样看:假设你有一间浴室,门上锁着,外面有一排人等着。浴室里的炸弹爆炸了,炸死了里面的人。您的问题是“在那种情况下,锁会自动解锁以便下一个人可以进入浴室吗?” 是的,它会。 这不是一件好事。一个炸弹刚刚在那里爆炸并杀死了一个人!水管可能被毁了,房子的结构已经不健全了,里面可能还有一颗炸弹。正确的做法是尽快让所有人离开并拆除整个房屋。
I mean, think it through: if you locked a region of code in order to read from a data structure without it being mutated on another thread, and something in that data structure threw an exception, odds are good that it is because the data structure is corrupt. User data is now messed up; you don't want to try to save user dataat this point because you are then saving corruptdata. Just terminate the process.
我的意思是,仔细考虑一下:如果你锁定了一个代码区域以便从一个数据结构中读取而不在另一个线程上发生变异,并且该数据结构中的某些东西抛出了异常,那么很可能是因为数据结构是腐败的。用户数据现在乱七八糟;此时您不想尝试保存用户数据,因为您正在保存损坏的数据。只需终止该过程。
If you locked a region of code in order to perform a mutation without another thread reading the state at the same time, and the mutation throws, then if the data was not corrupt before, it sure is now. Which is exactly the scenario that the lock is supposed to protect against. Now code that is waiting to read that state will immediatelybe given access to corrupt state, and probably itself crash. Again, the right thing to do is to terminate the process.
如果您锁定了一个代码区域以便在没有另一个线程同时读取状态的情况下执行突变,并且突变抛出,那么如果数据以前没有损坏,那么现在肯定是。这正是锁应该防止的情况。现在正在等待读取该状态的代码将立即获得对损坏状态的访问权限,并且可能本身崩溃。同样,正确的做法是终止进程。
No matter how you slice it, an exception inside a lock is bad news. The right question to ask is not "will my lock be cleaned up in the event of an exception?" The right question to ask is "how do I ensure that there is never an exception inside a lock? And if there is, then how do I structure my program so that mutations are rolled back to previous good states?"
无论你如何切片,锁内的异常都是坏消息。要问的正确问题不是“如果发生异常,我的锁会被清理吗?” 正确的问题是“我如何确保锁内永远不会出现异常?如果有,那么我如何构建我的程序,以便将突变回滚到以前的良好状态?”