Handling preemptive threads in callbacks (via declare)

In all the ideas to make the runtime more thread safe, the idea of having a code prefix on a method to get the lock, so it is the only thread running in the Xojo app, is the best we ever had!
In my opinion, it may be the most practical one.
We’ll see what Xojo engineers will say.

First of all, I would like to thank Thomas & Greg for this thread. Using @Joe Ranieri blocks plug-in, I have been able to implement more complex API into my Xojo built applications, however blocks on a different thread have been a PITA for me (especially as I lack the understand to solve this on my own), and so I am grateful for those who’ve helped here.

Currently I am using AVAssetWriter to create a movie file, it has the function finishWritingWithCompletionHandler: which from my understanding has no properties.
https://developer.apple.com/documentation/avfoundation/avassetwriter/1390432-finishwritingwithcompletionhandl?language=objc

Using only Greg’s solution, I still get the stackOverflowException and no further code is executed. If I add in Thomas’ #pragma stackOverflowChecking false, Greg’s timer solution does now work for me. I will admit that Thomas’ complete solution (of then re-routing the call to the main thread) seems like the way to go, but for the time being I am happy that this now works. There are other AVFoundation functions that I’ve ignored because of this situation, as I explore those (which have properties) I’ll look into comparing the two solutions.

Are there any concerns about ignoring stackOverflowExceptions?

p.s. Thanks again you two, you really helped me. I had previously patched over it in the app.unhandledException handler, but this just felt dirty to me.

@Sam Rowlands The pragma to ignore stack overflows is fine there.

Stack Overflow checking usually works like this:

The (CPU return & parameters) stack is a limited memory area. The CPU gets told where in memory it starts but not where it ends. In order to make sure a deep recursion does not reach outside this memory area, the compiler adds extra code, usually at the entrance of every function, to make sure the stack pointer is not going below a certain value, which is close to the stack’s limit. If it does, it’ll throw an exception.

Now, the nature of threads is that every thread has its own such stack. Meaning that for Xojo’s compiler-generated code, it has to known the limit for each of those threads, and identify the correct limit for the current thread from it. There are various ways to do this, and I don’t know Xojo’s method for this.

But the fact that we’re now dealing here with threads that are unknown to Xojo means that Xojo has not set up a stack limit value for that thread, either. So it may not be able to determine the correct stack limit for these threads and thus may make wrong assumptions and bail at that. That’s why you need to turn this checking off in these cases.

Thanks Thomas, I understand now. I am so happy that this now works (especially without it popping the IDE forwards). All these years, and the key (at least for this function) was to simply to disable the stackOverflowException…

Alright. I think I’ve solved it. I’ve made a module that effectively provides two functions that you’d call before and after accessing Xojo objects from an asynchronous thread, like this:

[code] #pragma StackOverflowChecking false
#pragma DisableBackgroundTasks

TTsSafeCallbacks.Enter (context) // everything after this until Leave() is thread-safe

gWindow.mTestArray.Append Str(context, “-#”) // this would crash normally, but not any more

TTsSafeCallbacks.Leave (context)[/code]

I will demonstrate this tomorrow at the MBS Xojo conference in Munich and will post a demo project afterwards.

Damn, I had to explain so much in my talk at the conference that I actually forgot to show the demo I had prepared. If you like to try for yourself, it’s here:

Index of /RB/Threading – it’s the “Safe threaded callbacks.rbp.zip” file.

It should run without ever crashing. If you get a crash, it would disprove my claim that I found a solution. Try to let it crash, I challenge everyone :slight_smile:

If no one gets a crash, maybe you like Xojo to add this feature natively? Then please support this feedback request:

<https://xojo.com/issue/53200>: ThreadSafeCallback pragma for callbacks

@Thomas Tempelmann I suppose the example is for Mac. Is there any chance you make one for Windows or cross platform.

Right. At the moment it works on Mac and should also work on Linux, due to me using pthreads.
There is also a pthreads dll for Windows. I wonder if including that will make it work on Win. Otherwise, one has to figure out which Win threading calls match the ones used from pthreads. Since I do not need this myself, I leave that up to others. Unless someone wants to pay me :slight_smile:

Thomas, you brought up a similar idea in Feb 2015 and Joe Ranieri gave good advice which is still appropriate today:

https://forum.xojo.com/20313-using-grand-central-dispatch-gcd-for-preemptive-threading

@Greg O’Lone Which of Ranieri’s advice do you mean? This one…

… I have proven wrong (unless proven otherwise) - see my posted demo project above.

Though - you have to differentiate between the discussion there, which was about trying to do concurrent multitasking in Xojo code, and this thread, which is only talking about making pre-emptive callbacks safer - without implied concurrency.

I agree with Joe Ranieri that concurrent (multi-CPU) threading can’t work in Xojo (unless it would get a huge overhaul, which even I don’t expect or wish to happen), but what can be done is making Xojo code in pre-emptive callbacks access Xojo objects safely, as I’ve demonstrated.

I have the impression that both you and Norman do not understand the mechanics behind all this and only refer to Joe’s single comment, which you apply incorrectly, i.e. with the wrong context.

I wish Joe would actually comment on my findings here, which were never discussed back then.

1 Like