Can Monitor.Enter throw an exception? - c#

Can Monitor.Enter throw any exception. I am doing a code review and find that Monitor.Enter is before try block. Do you see any issues with in?
Monitor.Enter(...)
try
{
...
}
finally
{
Monitor.Exit(..)
}

This is the correct pattern, whether Enter() throws (can throw) or not.
Only after the call to Enter() succeeds your code is under the responsibility to call Exit().
Suppose the call to Enter() fails. Then calling the corresponding Exit() is simply incorrect, it will make matters worse. So Enter() has to be outside (before) the try block.

Hans Passant's comment is of course correct. If Monitor.Enter throws before the lock is taken then you do not want the finally to run. If it throws after the lock is taken and after the try is entered, then the lock is released. (More on this later.) But if the throw happens after the lock is taken but before the try is entered, then the lock will never be cleaned up.
This is a rare but possible situation.
In C# 4 we changed the codegen of the lock statement so that the monitor enter is inside the try. This ensures that the lock is always released if something throws after the lock is taken. However, note that this might still be wrong. If something throws after the lock is taken then whatever non-atomic mutation the lock is protecting might be half-completed, and the finally block then unlocks the lock and allows access to the inconsistent state! The fundamental problem here is that you shouldn't be throwing inside a lock in the first place.
See my article about the issue for more discussion.

Monitor.Enter can throw at least the following exceptions
ArgumentNullException of the parameter is null
ThreadInterruptedException if the thread doing the Enter has it's Interrupt method invoked.

If it acquires the lock, then no.
But an exception might be thrown between the Monitor.Enter and the try block.
The recommended method is the new Enter method, new in .NET 4:
public static void Enter( obj, ref bool lockTaken )

Related

.net 2.0 lock and exceptions before the try-finally. Are there any other exceptions besides thread abort?

Today I've run into this:
https://blogs.msdn.microsoft.com/ericlippert/2009/03/06/locks-and-exceptions-do-not-mix/
I am using .net 2.0, so, basically, this code
lock(syncRootVar) {
DoStuff();
}
Will unfold into this
Monitor.Enter(syncRootVar);
try {
DoStuff();
} finally {
Monitor.Exit(syncRootVar);
}
As Lippert wrote on the blog, there might be a nop operation between the Enter call and the try-finally block, being a potential position for a thread abort exception to be raised and therefore messing up with the lock.
I have two questions about this:
Is there a common way of handling this troublesome situation and still clean up the lock object in order to not affect other threads?
Are there other situations that might result in the lock being acquired, but exceptions raising before the try-finally block?
As the article points out, the issue you seem to be concerned with is no longer an issue. The C# compiler has been changed (and presumably with Roslyn will retain the change) so that the lock is taken inside the try/finally. It's not possible to take the lock but fail to execute the finally clause.
Now (also as the article points out) you have a different problem: if the code in the protected block of code is mutating state, an exception could result in other code seeing partially-mutated state. This may or may not be a problem; usually it would be, but of course each specific scenario is different. It's possible some code would be safe in such a case.
• Is there a common way of handling this troublesome situation and still clean up the lock object in order to not affect other threads?
For the specific situation you've asked about, the two biggest things you can do are:
Don't abort threads. This is always good advice and should always be followed. If you don't abort a thread, you won't have that problem.
Use the latest version of the compiler. The newer versions of the compiler don't generate code that would be susceptible to the problem.
• Are there other situations that might result in the lock being acquired, but exceptions raising before the try-finally block?
No, not with the latest version of the compiler. There's not even the original situation.
Now what about that pesky "partially-mutated" issue? Well, you'll have to address each case individually. But if an exception might be thrown, and leaving the lock with partially-mutated state is possible, then you'll have to add your own clean-up code. E.g.:
lock(syncRootVar) {
try {
DoStuff();
} catch {
UndoStuff();
throw;
}
}

Can the (plain) throw statement in C# cause exceptions?

Question: Can the plain throw statement in C# ever cause a new exception in itself?
Note that I ask this question out of curiosity, not because I have any practical or real-world situation where it would matter much. Also note that my gut feeling and experience tell me that the answer is "No", but I'm looking to validate that answer somehow (see further down on sources I've tried so far).
Here's some sample code to illustrate my question:
try
{
int x = 0, y = 1 / x;
}
catch (Exception outerException)
{
try
{
throw;
}
catch (Exception innerException)
{
// Q: Does this Assert ever fail??
System.Diagnostics.Debug.Assert(outerException.Equals(innerException));
}
}
I'm wondering if there's any way at all to alter the circumstances such that the Assert will fail, without touching the inner try/catch block.
What I've tried or was looking to try to answer this:
Read the throw (C# Reference) page on MSDN - no definitive answer;
Checked part 5.3.3.11 of the C# Language Specification - which is probably the wrong place to look for this kind of info;
Glossed through the exceptions that I could try to trigger on the throw statement. The OutOfMemoryException comes to mind, but is kind of hard to trigger at the time of the throw.
Opened up ILDASM to check the generated code. I can see that throw translates to a rethrow instruction, but I'm lost where to look further to check if that statement can or cannot throw an exception.
This is what ILDASM shows for the inner try bit:
.try
{
IL_000d: nop
IL_000e: rethrow
} // end .try
So, to summarize: can a throw statement (used to rethrow an exception) ever cause an exception itself?
In my honest opinion, theoretically the assert can 'fail' (practically I don't think so).
How?
Note: Below are just my 'opinion' on the basis of some research I earlier did on SSCLI.
An InvalidProgramException can occur. This admittedly is highly highly improbable but nevertheless theoretically possible (for instance some internal CLR error may result in the throwable object becoming unavailable!!!!).
If CLR does not find enough memory to process the 're-throw' action it will throw an OutOfMemoryException instead (CLR's internal re-throw logic requires to allocate some memory if it is not dealing with 'pre-allocated' exceptions like OutOfMemoryException).
If the CLR is running under some other host (for e.g. SQL server or even your own) and the host decides to terminate the Exception re-throw thread (on the basis of some internal logic) ThreadAbortException (known as rude thread abort in this case) will be raised. Though, I am not sure if the Assert will even execute in this case.
Custom host may have applied escalation policy to CLR (ICLRPolicyManager::SetActionOnFailure). In that case if you are dealing with an OutOfMemoryException, escalation policy may cause ThreadAbortException to occur (again rude thread abort. Not sure what happens if policy dictates a normal thread abort).
Though #Alois Kraus clarifies that 'normal' thread abort exceptions are not possible, from SSCLI research I am still doubtful that (normal) ThreadAbortException can occur.
Edit:
As I earlier said that the assert can fail theoretically but practically it is highly improbable. Hence it is very hard to develop a POC for this.
In order to provide more 'evidence', following are the snippets from SSCLI code for processing rethow IL instruction which validate my above points.
Warning: Commercial CLR can differ very widely from SSCLI.
InvalidProgramException :
if (throwable != NULL)
{
...
}
else
{
// This can only be the result of bad IL (or some internal EE failure).
RealCOMPlusThrow(kInvalidProgramException, (UINT)IDS_EE_RETHROW_NOT_ALLOWED);
}
Rude Thread Abort :
if (pThread->IsRudeAbortInitiated())
{
// Nobody should be able to swallow rude thread abort.
throwable = CLRException::GetPreallocatedRudeThreadAbortException();
}
This means that if 'rude thread abort' has been initiated, any exception gets changed to rude thread abort exception.
Now most interesting of all, the OutOfMemoryException. Since rethrow IL instruction essentially re-throws the same Exception object (i.e. object.ReferenceEquals returns true) it seems impossible that OutOfMemoryException can occur on re-throw. However, following SSCLI code shows that it is possible:
// Always save the current object in the handle so on rethrow we can reuse it. This is important as it
// contains stack trace info.
//
// Note: we use SafeSetLastThrownObject, which will try to set the throwable and if there are any problems,
// it will set the throwable to something appropiate (like OOM exception) and return the new
// exception. Thus, the user's exception object can be replaced here.
throwable = pThread->SafeSetLastThrownObject(throwable);
SafeSetLastThrownObject calls SetLastThrownObject and if it fails raises OutOfMemoryException. Here is the snippet from SetLastThrownObject (with my comments added)
...
if (m_LastThrownObjectHandle != NULL)
{
// We'll somtimes use a handle for a preallocated exception object. We should never, ever destroy one of
// these handles... they'll be destroyed when the Runtime shuts down.
if (!CLRException::IsPreallocatedExceptionHandle(m_LastThrownObjectHandle))
{
//Destroys the GC handle only but not the throwable object itself
DestroyHandle(m_LastThrownObjectHandle);
}
}
...
//This step can fail if there is no space left for a new handle
m_LastThrownObjectHandle = GetDomain()->CreateHandle(throwable);
Above code snippets shows that the throwable object's GC handle is destroyed (i.e frees up a slot in GC table) and then a new handle is created. Since a slot has just been released, new handle creation will never fail until off-course in a highly rare scenario of a new thread getting scheduled just at the right time and consuming up all the available GC handles.
Apart from this all exceptions (including rethrows) are raised through RaiseException win api. The code that catches this exception to prepare the corresponding managed exception can itself raise OutOfMemoryException.
Can the plain throw statement in C# ever cause a new exception in itself?
By definition it won't. The very point of throw; is to preserve the active exception (especially the stack-trace).
Theoretically an implementation could maybe clone the exception but what would be the point?
I suspect the bit you're missing may be the specification for rethrow, which is within ECMA-335, partition III, section 4.24:
4.24 rethrow – rethrow the current exception
Description:
The rethrow instruction is only permitted within the body of a catch handler (see
Partition I). It throws the same exception that was caught by this handler.
A rethrow does not change the stack trace in the object.
Exceptions:
The original exception is thrown.
(Emphasis mine)
So yes, it looks like your assertion is guaranteed to work according to the spec. (Of course this is assuming an implementation follows the spec...)
The relevant part of the C# specification is section 8.9.5 (C# 4 version):
A throw statement with no expression can be used only in a catch block, in which case that statement re-throws the exception that is currently being handled by that catch block.
Which again, suggests that the original exception and only that exception will be thrown.
(Section 5.3.3.11 which you referred to is just talking about definite assignment, not the behaviour of the throw statement itself.)
None of this invalidates Amit's points, of course, which are for situations which are somewhat outside the scope of what's specified in either place. (When hosts apply additional rules, it's hard for a language specification to take account of them.)
Your assertion will never fail because there is no code between the rethrow and the assertion. The only way an exception changes if you catch the exception and cause another one - eg. by having buggy code or "throw new" in your catch clause,.
Combined with recursion plain throw can easily cause StackOverflowException on 64-bit platforms.
class Program
{
// expect it to be 10 times less in real code
static int max = 455;
static void Test(int i)
{
try {
if (i >= max) throw new Exception("done");
Test(i + 1);
}
catch {
Console.WriteLine(i);
throw;
}
}
static void Main(string[] args)
{
try {
Test(0);
}
catch {
}
Console.WriteLine("Done.");
}
}
In console:
...
2
1
0
Process is terminated due to StackOverflowException.
Some explanation may be found here.

Exception during lock [duplicate]

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:
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.
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.
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 data at this point because you are then saving corrupt data. 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 immediately be 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?"
First; have you considered 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:
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.
So it will be released in all but the most fatal catastrophic unrecoverable exceptions.
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.
If you really want to know, a lock in C#4 / .NET 4 is:
{
bool haveLock = false;
try {
Monitor.Enter(myLock, ref haveLock);
} finally {
if(haveLock) Monitor.Exit(myLock);
}
}
"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.
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."
Taken from:
This site
Just to add a little to Marc's excellent answer.
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.
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.
Your lock will be released properly. A lock acts like this:
try {
Monitor.Enter(myLock);
// ...
} finally {
Monitor.Exit(myLock);
}
And finally blocks are guaranteed to execute, no matter how you leave the try block.

locking a resource via lock within try. Is it wrong?

Is there anything wrong with using lock with a try block? I remember reading somewhere that we should always try to put minimum amount of code within try block and lock itself internally uses a try-finally block, do you guys see something wrong here.I need to deal with the fact that the code within that lock block can throw exception
try
{
lock(syncblk)
{
// do some processing
}
}
catch(Exception e)
{
// do something with exception
}
I need to deal with the fact that the code within that lock block can throw exception
And there's your problem. That's a terrible situation to be in.
Why are you locking in the first place? Usually the reason why you lock something is because you want to implement the following logic:
lock the door
make a mess
clean it up
unlock the door
If you do that, then no one who honours the locked door ever sees the mess.
For example, you might want to swap values of variables "left" and "right" in a threadsafe manner, so you:
take the lock
read the left variable into tempLeft
read the right variable into tempRight
write tempLeft into right
we just made a mess; the original value of 'right' has gone missing
write tempRight into left
we've cleaned up the mess, all is well with the world again
release the lock
Now suppose an exception is thrown after the mess is made. What happens? We jump straight to the unlock, leaving the mess for another thread to see.
That's why you should never throw an exception inside a lock; it completely defeats the purpose of the lock! The whole point of a lock is to ensure that state is always observed to be consistent by all threads except the one responsible for cleaning up the mess.
If you have an exception that can be thrown from inside a lock, the best thing to do is to get out of that horrible situation. If you can't do that, then make sure that you can either (1) destroy the process utterly as soon as the exception escapes the lock, so that the mess you made cannot cause data loss or other harm -- do a FailFast and nuke the process from orbit, it's the only way to be sure -- or (2) write rollback code that undoes whatever operation you were attempting before the lock is exited; that is, clean up the mess back to the original state.
If the latter is your strategy then don't put the try block outside the lock; it's useless there because the instant control leaves the lock via the exception another thread can be crashing and dying because of the mess you left exposed to it. Put the try that deals with the exception inside the lock:
lock(whatever)
{
try
{
MakeAMess();
}
finally
{
CleanItUp();
// Either by completing the operation or rolling it back
// to the pre-mess state
}
}
If you have strong reliability requirements then dealing with locked critical sections which can throw exceptions is an extremely difficult programming task best left to experts; you might consider using a constrained execution region if you find yourself in this situation a lot.
I think you can do it your way but here is the MSDN description on lock for your information. Please refer to http://msdn.microsoft.com/en-us/library/ms173179.aspx for more info.
Using the lock (C#) or SyncLock
(Visual Basic) keyword is generally
preferred over using the Monitor class
directly, both because lock or
SyncLock is more concise, and because
lock or SyncLock insures that the
underlying monitor is released, even
if the protected code throws an
exception. This is accomplished with
the finally keyword, which executes
its associated code block regardless
of whether an exception is thrown.
So I am not sure what kind of exception you are referring to but if you concern is that you may not be able to release the lock because of exception, you do not have to worry about it.
you can always use the longer syntax like this:
System.Threading.Monitor.Enter(x);
try {
...
}
catch(Exception e)
{
}
finally {
System.Threading.Monitor.Exit(x);
}

Is C#'s using statement abort-safe?

I've just finished reading "C# 4.0 in a Nutshell" (O'Reilly) and I think it's a great book for a programmer willing to switch to C#, but it left me wondering. My problem is the definition of using statement. According to the book (p. 138),
using (StreamReader reader = File.OpenText("file.txt")) {
...
}
is precisely equivalent to:
StreamReader reader = File.OpenText("file.txt");
try {
...
} finally {
if (reader != null)
((IDisposable)reader).Dispose();
}
Suppose, however, that this is true and that this code is executed in a separate thread. This thread is now aborted with thread.Abort(), so a ThreadAbortException is thrown and suppose the thread is exactly after initializing the reader and before entering the try..finally clause. This would mean that the reader is not disposed!
A possible solution would be to code this way:
StreamReader reader = null;
try {
reader = File.OpenText("file.txt");
...
} finally {
if (reader != null)
((IDisposable)reader).Dispose();
}
This would be abort-safe.
Now for my questions:
Are authors of the book right and the using statement is not abort-safe or are they wrong and it behaves like in my second solution?
If using is equivalent to the first variant (not abort-safe), why does it check for null in finally?
According to the book (p. 856), ThreadAbortException can be thrown anywhere in managed code. But maybe there are exceptions and the first variant is abort-safe after all?
EDIT: I know that using thread.Abort() is not considered good practice. My interest is purely theoretical: how does the using statement behave exactly?
The book's companion web site has more info on aborting threads here.
In short, the first translation is correct (you can tell by looking at the IL).
The answer to your second question is that there may be scenarios where the variable can be legitimately null. For instance, GetFoo() may return null here, in which you wouldn't want a NullReferenceException thrown in the implicit finally block:
using (var x = GetFoo())
{
...
}
To answer your third question, the only way to make Abort safe (if you're calling Framework code) is to tear down the AppDomain afterward. This is actually a practical solution in many cases (it's exactly what LINQPad does whenever you cancel a running query).
There's really no difference between your two scenarios -- in the second, the ThreadAbort could still happen after the call to OpenText, but before the result is assigned to the reader.
Basically, all bets are off when you get a ThreadAbortException. That's why you should never purposely abort threads rather than using some other method of gracefully bringing the thread to a close.
In response to your edit -- I would point out again that your two scenarios are actually identical. The 'reader' variable will be null unless the File.OpenText call successfully completes and returns a value, so there's no difference between writing the code out the first way vs. the second.
Thread.Abort is very very bad juju; if people are calling that you're already in a lot of trouble (unrecoverable locks, etc). Thread.Abort should really be limited to the scanerio of inhuming a sickly process.
Exceptions are generally unrolled cleanly, but in extreme cases there is no guarantee that every bit of code can execute. A more pressing example is "what happens if the power fails?".
Re the null check; what if File.OpenText returned null? OK, it won't but the compiler doesn't know that.
A bit offtopic but the behaviour of the lock statement during thread abortion is interesting too. While lock is equivalent to:
object obj = x;
System.Threading.Monitor.Enter(obj);
try {
…
}
finally {
System.Threading.Monitor.Exit(obj);
}
It is guaranteed(by the x86 JITter) that the thread abort doesn't occur between Monitor.Enter and the try statement.
http://blogs.msdn.com/b/ericlippert/archive/2007/08/17/subtleties-of-c-il-codegen.aspx
The generated IL code seems to be different in .net 4:
http://blogs.msdn.com/b/ericlippert/archive/2009/03/06/locks-and-exceptions-do-not-mix.aspx
The language spec clearly states that the first one is correct.
http://msdn.microsoft.com/en-us/vcsharp/aa336809.aspx MS Spec(Word document)
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf ECMA Spec
In case of a thread aborting both code variants can fail. The second one if the abort occurs after the expression has been evaluated but before the assignment to the local variable occurred.
But you shouldn't use thread abortion anyways since it can easily corrupt the state of the appdomain. So only abort threads if you force unload an appdomain.
You are focusing on the wrong problem. The ThreadAbortException is just as likely to abort the OpenText() method. You might hope that it is resilient to that but it isn't. The framework methods do not have try/catch clauses that try to deal with a thread abort.
Do note that the file doesn't remain opened forever. The FileStream finalizer will, eventually, close the file handle. This of course can still cause exceptions in your program when you keep running and try to open the file again before the finalizer runs. Albeit that this is something you always have to be defensive about when you run on a multi-tasking operating system.
Are authors of the book right and the using statement is not abort-safe or are they wrong and it behaves like in my second solution?
According to the book (p. 856), ThreadAbortException can be thrown anywhere in managed code. But maybe there are exceptions and the first variant is abort-safe after all?
The authors are right. The using block is not abort-safe. Your second solution is also not abort-safe, the thread could be aborted in the middle of the resource acquisition.
Although it's not abort-safe, any disposable that has unmanged resources should also implement a finalizer, which will eventually run and clean up the resource. The finalizer should be robust enough to also take care of not completely initialized objects, in case the thread aborts in the middle of the resource acquisition.
A Thread.Abort will only wait for code running inside Constrained Execution Regions (CERs), finally blocks, catch blocks, static constructors, and unmanaged code. So this is an abort-safe solution (only regarding the acquisition and disposal of the resource):
StreamReader reader = null;
try {
try { }
finally { reader = File.OpenText("file.txt"); }
// ...
}
finally {
if (reader != null) reader.Dispose();
}
But be careful, abort-safe code should run fast and not block. It could hang a whole app domain unload operation.
If using is equivalent to the first variant (not abort-safe), why does it check for null in finally?
Checking for null makes the using pattern safe in the presence of null references.
The former is indeed exactly equivalent to the latter.
As already pointed out, ThreadAbort is indeed a bad thing, but it's not quite the same as killing the task with Task Manager or switching off your PC.
ThreadAbort is an managed exception, which the runtime will raise when it is possible, and only then.
That said, once you're into ThreadAbort, why bother trying to cleanup? You're in death throes anyway.
the finally-statement is always executed, MSDN says "finally is used to guarantee a statement block of code executes regardless of how the preceding try block is exited."
So you don't have to worry about not cleaning resources etc (only if windows, the Framework-Runtime or anything else bad you can't control happens, but then there are bigger problems than cleaning up Resources ;-))

Categories

Resources