Reputation: 709
I have a c# program which acts as client and many client program which is again a c# windows application connects to this c# server program to read data from sqlite database. To avoid lock issues when connecting multiple clients i have used below code,
System.Threading.Monitor.Enter(Lock);
try
{
filter.Execute();//get data from database
Request.Clear();
return filter.XML;//create xml and return to client
}
finally
{
System.Threading.Monitor.Exit(Lock);
}
server gets hangs some times and need to restart the server program. Is it a good practce to make the return statement before finally?
Regards sangeetha
Upvotes: 5
Views: 1485
Reputation: 19161
As you have no catch block, there is no guarantee that finally will be executed. From MSDN - try-finally (C# Reference) and "Locks and exceptions do not mix" (Eric Lippert)
Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. That, in turn, is dependent on how your computer is set up.
And from the link that is then mentioned (Unhandled Exception Processing In The CLR) there are then various considerations which could mean you end up with a terminated thread. I don't honestly know if that would leave you with a lock on the lock object though.
If you wanted to ensure that:
Then do:
TheXmlType xml = null;
Monitor.Enter(Lock);
bool inLock = true;
try {
...
xml = filter.Xml; // put this here in case it throws an exception
inLock = false; // set this here in case monitor.exit is to
// throw an exception so we don't do the same all over again in the catch block
Monitor.Exit(Lock);
return xml; // this is fine here, but i would normally put it outside my try
}
catch (Exception) {
if (inLock) Monitor.Exit(Lock);
throw;
}
But, please note: don't use catch (Exception)
to hide exceptions, this is only ok if you are re-throwing the exception. People also recommend you have a single return
statement, and usually this would be outside your try block.
EDIT:
Confirmed with a test program, and from MSDN - Exceptions in Managed Threads
Starting with the .NET Framework version 2.0, the common language runtime allows most unhandled exceptions in threads to proceed naturally. In most cases this means that the unhandled exception causes the application to terminate.
So, if you don't handle your exception, your application will crash (and you won't have to worry about the lock). If you do handle it, then your original code would execute it's finally block and you are ok.
EDIT 2: Test code updated as it did not properly illustrate a non-firing finally:
class Program
{
static void Main(string[] args) {
Program p =new Program();
p.Start();
Console.WriteLine("done, press enter to finish");
Console.ReadLine();
}
private readonly object SyncRoot = new object();
ManualResetEvent mre = new ManualResetEvent(false);
private void Start() {
/*
* The application will run the thread, which throws an exception
* While Windows kicks in to deal with it and terminate the app, we still get
* a couple of "Failed to lock" messages
* */
Thread t1 = new Thread(SetLockAndTerminate);
t1.Start();
mre.WaitOne();
for (int i = 0; i < 10; i++) {
if (!Monitor.TryEnter(this.SyncRoot, 1000)) {
Console.WriteLine("Failed to lock");
}
else {
Console.WriteLine("lock succeeded");
return;
}
}
Console.WriteLine("FINALLY NOT CALLED");
}
public int CauseAnOverflow(int i)
{
return CauseAnOverflow(i + 1);
}
public void SetLockAndTerminate() {
Monitor.Enter(this.SyncRoot);
Console.WriteLine("Entered");
try {
mre.Set();
CauseAnOverflow(1); // Cause a stack overflow, prevents finally firing
}
finally {
Console.WriteLine("Exiting");
Monitor.Exit(this.SyncRoot);
}
}
}
Upvotes: 1
Reputation: 1240
Is it bad practice to return from within a try catch finally block?
It is the right way of writing Exception Handling in c# and always finally block will be executed it does not depend on the place of return.
I do not know about your code but you should find your problem somewhere else (for example if your code was hosted in IIS I would suspect the state of Lock object in different loaded domains or maybe the lock is just for one incoming call and it happens in database or what is Request.Clear() you don't have a lock block there?). You can easily log the state of incoming calls and find the problem.
Upvotes: 0
Reputation: 13033
Yes, it's what finally
statement is for. It will be executed after the return
, even if an exception occurs
EDIT: this simple code will show you, that catch block is not needed for finally block to be executed
public Form1()
{
InitializeComponent();
check();
}
private string check()
{
try
{
return String.Empty;
}
finally
{
MessageBox.Show("finally");
}
}
Upvotes: 2
Reputation: 13207
From MSDN
By using a finally block, you can clean up any resources that are allocated in a try block, and you can run code even if an exception occurs in the try block. Typically, the statements of a finally block run when control leaves a try statement. The transfer of control can occur as a result of normal execution, of execution of a break, continue, goto, or return statement, or of propagation of an exception out of the try statement.
Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. That, in turn, is dependent on how your computer is set up. For more information, see Unhandled Exception Processing in the CLR.
Upvotes: 4