Does a locked object stay locked if an exception occurs inside it?
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.
Exceptions inside the lock block
Lock will be released when exception escapes from the lock block.
That is because lock(){...}
is translate by compiler roughly into:
Monitor.Enter(obj);
try{
// contents of the lock block
}finally{
Monitor.Exit(obj);
}
Lock statement - does it always release the lock?
In 4.0 implementation if a thread abort or any cross thread exception occurs just before the
Monitor.Exit(temp)
in the finally block is executed - would that keep the lock on the object?
Let's take a look at that code, so that it is clear to other readers:
bool lockWasTaken = false;
var temp = obj;
try
{
Monitor.Enter(temp, ref lockWasTaken);
{
body
}
}
finally
{
if (lockWasTaken)
{
// What if a thread abort happens right here?
Monitor.Exit(temp);
}
}
Your question is not answerable because it is based on a false assumption, namely, that thread aborts can happen in the middle of a finally block.
Thread aborts cannot happen in the middle of a finally block. That is just one reason amongst many reason why you should never attempt to abort a thread. The entire thread could be running in a finally block, and therefore be not-abortable.
Is there any possibility for an exception to occur at this level, leaving the object still in a locked state?
No. A thread abort will be delayed until control leaves the finally. Unlocking a valid lock does not allocate memory or throw another exception.
How long will a C# lock wait, and what if the code crashes during the lock?
When another thread comes by and wants to execute the code, how long will it wait until the lock is released?
lock
will block the the thread trying to enter the lock indefinitely until the object being locked on is released.
can you somehow set a timeout?
If you need to specify a timeout, use Monitor.TryEnter
as in
if(Monitor.TryEnter(obj, new TimeSpan(0, 0, 1))) {
try {
body
}
finally {
Monitor.Exit(obj);
}
}
if the
DoIt()
method throws an exception, is the lock still released?
Yes, a lock(obj) { body }
is translated to:
bool lockWasTaken = false;
var temp = obj;
try { Monitor.Enter(temp, ref lockWasTaken); { body } }
finally { if (lockWasTaken) Monitor.Exit(temp); }
For the gory details on what can happen when an exception is thrown, see Locks and exceptions do not mix.
What happens when a thread crashes holding a lock(SyncObject)?
lock(obj) { ... }
is just a syntactic sugar for
Monitor.Enter(obj);
try
{ ... }
finally
{
Monitor.Exit(obj);
}
and in C# 4.0 it was changed to
bool acquaired = false;
try
{
Monitor.Enter(obj, ref acquired);
...
}
finally
{
if (acquired)
{
Monitor.Exit(obj)
}
}
Now, prior to .Net 4.0, it was possible that ThreadAbortException
would be thrown between the Monitor.Enter(obj);
and the beginning of the try block - and that would've created a dead lock (which means, no thread can access the lock, and they would remain blocked). Now even this is impossible. Anyway, event if an exception was thrown inside the lock, the lock would be released because of the finally block.
** I believe @Jon Skeet deserve credit for this.
Nested lock in Task.ContinueWith - Safe, or playing with fire?
No it will not burn you. Even if the ContinueWith
is inlined into to the current thread that was running the new Task(() => new DatafeedUploadHandler()..
it will get the lock e.g. no dead lock.
The lock
statement is using the Monitor
class internally, and it is reentrant
. e.g. a thread can aquire a lock multiple times if it already got/owns the lock. Multithreading and Locking (Thread-Safe operations)
And the other case where the task.ContinueWith
starts before the ProcessModifiedDatafeed
finished is like you said. The thread that is running the ContinueWith
simply would have to wait to get the lock.
I would really consider to do the task.ContinueWith
and the task.Start()
outside of the lock if you reviewed it. And it is possible based on your posted code.
You should also take a look at the ConcurrentDictionary in the System.Collections.Concurrent
namespace. It would make the code easier and you dont have to manage the locking yourself. You are doing some kind of compare exchange/update here if (this.fileWatcherDictionary.ContainsNonNullKey(eventArgs.FullPath))
. e.g. only add if not already in the dictionary. This is one atomic operation. There is no function to do this with a ConcurrentDictionary
but there is an AddOrUpdate method. Maybe you can rewrite it by using this method. And based on your code you could safely use the ConcurrentDictionary
at least for the runningTaskDictionary
Oh and TaskCreationOptions.LongRunning
is literally creating a new thread for every task which is kind of an expensive operation. The windows internal thread pool is intelligent in new windows versions and is adapting dynamically. It will "see" that you are doing lots of IO stuff and will spawn new threads as needed and practical.
Greetings
locking a resource via lock within try. Is it wrong?
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.
Related Topics
Weak Event Handler Model for Use with Lambdas
C# Entity-Framework: How to Combine a .Find and .Include on a Model Object
How to Create an Expression Tree to Represent 'String.Contains("Term")' in C#
Calculated Column in Ef Code First
Struct Constructor: "Fields Must Be Fully Assigned Before Control Is Returned to the Caller."
How to Calculate the Sum of the Datatable Column in ASP.NET
Entity Framework Thread Safety
Display Unicode Characters in Converting HTML to PDF
Is SQLcommand.Dispose() Required If Associated SQLconnection Will Be Disposed
Get Value of C# Dynamic Property via String
Difference Between Char.Isdigit() and Char.Isnumber() in C#
Generic Way to Check If Entity Exists in Entity Framework
App.Config for a Class Library
Unhandled Exceptions in Backgroundworker
How to Not Serialize the _Type Property on JSON Objects