Your program is terminating because it has reached an exception it wasn’t designed to handled. That’s how the UnhandledException system is supposed to work.
If you can handle the exception, catch its type specifically, handle it, and carry on.
If you can’t, it needs to bubble and, for the third time, your app needs to Terminate.
Then, that outer handler as part of “catch its type specifically, handle it, and carry on” needs to unlock the CriticalSection. I shouldn’t have to iterate over every possible design to get the point across of when finally is executed.
For clarity it would not be executed if an exception were handled by an “outer handler”. The code would carry on from that “outer handler” catch statement.
Reading the documentation on Finally. There is an alternative version that makes sense in this circumstance:
Var CSEntered as Boolean = false
Try
CriticalSection.Enter
CSEntered = True
DB.BeginTransaction
[Do sqlite things that do not directly or indirectly involve entering or leaving critical section]
DB.CommitTransaction
Catch oError as DatabaseExcpetion
DB.RollbackTransaction
End Try
// This Finally operates even if there is an unhandled exception.
Finally
if CSEntered then CriticalSection.Leave
Notes: Sometimes a method needs to do some cleanup work whether it is finishing normally or aborting early because of an exception. The optional Finally block at the end of a method or function runs after its exception handlers, if it has any. Code in this block will be executed even if an exception has occured, whether the exception was handled or not.
There seems to be a misunderstanding about Try...Finally. The Finally clause will execute regardless of the number or type of Catch clauses.
Consider:
Try
Raise New DatabaseException
Catch Err As UnsupportedFormatException
Break // Never executed
Finally
Break // always executed
End Try
Break // executed only if no exceptions are raised and uncaught
The only way the Finally clause would not execute is if there is a Return statement in the Catch clause.
Try
Raise New DatabaseException
Catch Err As DatabaseException
Return // don't do this
Finally
Break
End Try
Not if there is an Exception that is not handled. Nothing after the line that causes the exception executes. The difference of opinion is if the Critical section should be "leave"d if an unhandled exception occurs.
One will always get both breaks or neither break. One would never get just one of them. The code from your // don't do this example would operate functionally the same as well.
I think how Finally works is subtle, and not necessarily intuitive - but definitely useful.
Imagine this code:
App.unhandledException
system.DebugLog "E App.UnhandledException"
App.Open
try
system.DebugLog "A Try: about to raise exception"
raise new RuntimeException
system.DebugLog "B Try: after exception"
finally
system.DebugLog "C Finally clause running"
end try
system.DebugLog "D After End Try"
What you get is this:
A Try: about to raise exception
C Finally clause running
E App.unhandledException
To me this is interesting, as the Finally clause happens before the exception bubbles up out of the method.