Illegal Locking Exception

Currently pulling out my hair trying to find the cause of an illegallockingexception that occurs only in the built app, not in debug.

I am using multiple threads with a critical section related to db access. I’ve scoured the code for any enter/leave overlaps and haven’t found any.

This is the error info:

IllegalLockingException

CriticalSection.Leave%%o
Thread._InternalDispatchEvents%%oo
DesktopApplication._CallFunctionWithExceptionHandling%%op
REALbasic._RuntimeRun
_Main
wWinMain
__tmainCRTStartup

Look familiar to anyone?

IDE on Windows 10 64-bit.
64 GB RAM available.
Xojo v2024r3.1
Desktop app - Windows 64-bit only
Various MBS plugins active

Thanks,
Will

You are probably calling .Leave once too much.

A .Lock must be cleared with a .Leave but you must never call .Leave without a .Lock before it.

2 Likes

Consider exception paths as well as standard code flow. Is it possible that you are locking within a Try block and unloading at the end of a method, or something more complicated along those lines?

The reason it doesn’t show in debug is that preemptive threads are only active in built applications.

I can’t find the post (or video) in witch @Paul_Lefebvre said this, but i think they are also real preemptive now in debug builds. :thinking:

That would be great. I don’t recall seeing it. In which version?

I’m not sure when or where I read or heard this. I seem to remember it being in a video (on YouTube? maybe this one?) . A presentation where @Geoff_Perlman was speaking and @Paul_Lefebvre assured him that preemptive threads are preemptive even during debugging.

I suspect you’re thinking of William. I’ve not been on any webinars regarding preemptive threads. But yes, preemptive threads are preemptive when debugging, although they are slower than they are in built apps.

4 Likes

First, I should have specified in my original post that I am using coop threads, not preemptive, but the discussion has been interesting.

Second, related to Ian’s observation about exceptions, I wonder whether my approach to combining Try/Catch with critical sections is correct. The approach I use is as follows:

Try
CriticalSection.Enter
DB.BeginTransaction
[Do sqlite things that do not directly or indirectly involve entering or leaving critical section]
DB.CommitTransaction
CriticalSection.Leave

Catch Bad Things
DB.RollbackTransaction
CriticalSection.Leave

End Try

Is this the proper structure or is there a better approach?

Thanks,
Will

Perhaps use Finally?

https://documentation.xojo.com/api/language/finally.html

2 Likes

Anything after end try is “finally” in my book :man_shrugging:

It was William but yes, that’s correct.

1 Like

A couple of things. When posting code highlight it and press the </> button (or place ``` before and after it) It makes it readable and prevents " being turned into smart quotes.

Secondly, this is the format that others are suggesting. The Finally section of Try / Catch block gets executed no matter what happens with the exception. It happens after the Try, and after the Catch if it occurs. Perfect for this sort of thing. It becomes even more useful if you have more than one Catch block, which is allowed.

Try
   CriticalSection.Enter
   DB.BeginTransaction
   [Do sqlite things that do not directly or indirectly involve entering or leaving critical section]
   DB.CommitTransaction

Catch Bad Things
   DB.RollbackTransaction

Finally
   CriticalSection.Leave

End Try
4 Likes

That is very helpful. Thanks.

Unless an exception occours that was not added to the try catch. That’s where Finally was meant for.

Finally would not execute in that case. If the exception was not part of the try...catch it would bubble to App.UnhandledException and the rest of the code would not execute.

Finally is “the try part completed or the catch part completed”, which really is synonymous with “anything after end try”. It’s a stylistic choice really, but I’d have written Ian’s sample with the try...catch being exclusively database code, and the CriticalSection being handled outside the statement.

1 Like

Tim is correct.

Also of concern is something that would re-raise the exception from within a catch block. Which could cause the Finally to fail to execute. That said putting it outside of the Try Catch block would fail too, if the exception is allowed to propagate back out of the method.

Perhaps the best format is as follows:

Try
   CriticalSection.Enter
   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

Catch oError as RuntimeException
   // We're about to crash out of this method, tidy up
   CriticalSection.Leave
   RaiseException oError // This prevents Finally and any code after this

Finally
   CriticalSection.Leave

End Try
1 Like

One should NEVER catch ex as RuntimeException. If the code isn’t designed to handle a specific exception, the exception needs to bubble to UnhandledException and the app needs to terminate.

I’ve been trying to avoid plain old writing the code, to allow the reader to exercise their creativity, but this try...catch is specifically for Database code and DatabaseExceptions. In my opinion, that’s a cleaner, more straightforward design.

CriticalSection.Enter

try
  DB.BeginTransaction
  // Do database things
  DB.CommitTransaction

catch ex as DatabaseException
  DB.RollbackTransaction

end try

CriticalSection.Leave

This is functionally the same as a finally statement. The key difference is that this doesn’t “catch all” exceptions, because again, one should never do that.

1 Like

That never calls leave if there is an unhandled exception. I deliberately dealt with the re-raising of the two exceptions that needs to bubble for app / thread termination. It bubbles all unhandled exceptions but tidies the Critical Exception too.

Quite intentionally so.

If there are no other exception handler blocks that would happen, just as it does now. Leaving the Critical section locked is likely going to hang your program.