Preemptive Pitfalls

When Preemptive Threads arrive, the first, best advice I can give you is…

Don’t. Use. Them.

If all you need is for your GUI to remain responsive while something happens in the background that doesn’t take that much time, you’ll be better off with the existing cooperative threads.

If you do have a compelling reason, you will have to consider things that, frankly, you’ve never had to consider in Xojo before. Unless you’ve had experience with preemptive threads in other languages, you might think you’re ready.

Trust me, you’re not.

Consider this seemingly straightforward pseudo-code:

do
  if getTheNextDataToProcess then
    processData
    continue loop
  end if

  if noMoreDataIsComing then
    exit loop
  end if
loop

This looks for data and, if none is there and no more is expected, we can declare it done and exit. This would work just fine in a cooperative thread.

Simple, right?

Not so fast. Because this is preemptive, things can happen simultaneously or within nanoseconds of something else. In this code, unless you’ve taken precautions, you could have added data, then told the thread that no more was coming after the getTheNextDataToProcess call, but before it checks noMoreDataIsComing.

The loop would find no data then exit because it thinks it’s done, even though more data was added in between.

Xojo will provide tools to help mitigate these issues, but these are still things you’ll have deal with.

And since this pseudo-code represents an actual failure that took two days to track down, believe me when I say, it won’t be fun.

9 Likes

Tools such as…? Without violating the testing NDA, of course.

At this stage, just “tools”. :slight_smile:

Thank you @Kem_Tekinay for your insight.

Since the announcement, the preemptive thread idea has been on the back-burner of my brain often. I spent most of my active career (25+ years) as a C# developer, and it was very rare that I required such a mechanism.

I think Xojo could definitely benefit from having preemptive threading as an option, but their use should be cautiously considered. A common point of frustration I foresee is not unlike the misuse of DoEvents() in Desktop apps.

In the meantime, I’m fine with how the single main/cooperative thread logic currently works. When preemptive arrives, I have a use case in mind for the future and look forward to experimenting with it.

1 Like

remembers me about my blog post:

Preemptive vs. cooperative threads in Xojo

There is always the chance that some other thread comes between you check the array and take an entry.

2 Likes

Christian, your post ends with a warning that Xojo already has preemptive threads on Android. What does this mean?

1 Like

Well… I have, and probably anyone that wrote low level code also, and they can forecast pitfalls need to isolate and protect and lock exclusive access of part of the data. Or write accessors with such lock/release internalized to make it easy when possible.

Yes, it may be for some, kind of the same effort they had to understand OOP when they arrived from procedural programming.

If Xojo did it ok, no worries. But I’m afraid on the how fresh this is to Xojo…

I’m intrigued but cautious about preemptive threads. I think I’ll initially use them as mostly self-contained data munchers – one of my projects could benefit from multiple independent parsers without the overhead of spinning up a Worker and copying the data back and forth.

I only want to use one preemptive thread. The Valentina database plugin shows the beachball for longer operations. Users have been trained to kill any app showing the beachball. Unfortunately, I never got the Valentina guys to show any interest in this.

Do plugins have to be changed to support preemptive threads?

I will have a perfect use case for preemptive thread as i will be processing thousands of text files which might gain much time

Kem,

Does this preemptive threading capability can be run across multiple processor cores? or is the execution is still limited within a single processor core?

You could potentially have the same problem with cooperative threads if a context switch occurs after getTheNextDataToProcess and before / during noMoreDataIsComing.

At minimum, the code should be performing one more loop iteration when the loop detects that noMoreDataIsComing becomes true.

It’ll be on multiple cores.

Preemptive threads are more difficult since you need to surround access to any job queue with a semaphore, mutex or critical section.

The Thread itself should be the only one to signal whether its work is done and whether it is time to process data collected in this Thread. Monitoring another Thread in preemptive interaction is often delicate/difficult/unsafe. :face_with_peeking_eye:
For starters i would recommend to not wait for such a Thread to be finished, but instead monitor Signals the Thread is giving to Systems monitoring this Threads activitys. Correct? :slight_smile:

Like so:

do
  if getTheNextDataToProcess_Signalled then
    processData
    continue loop
  end if

  if allDataHasBeenProcessed_Signalled and noMoreDataIsComing_Signalled then
    exit loop
  end if
loop

Then it would be worth the potential pitfalls.
No pain no gain.

1 Like

In another language perhaps, but in Xojo, context switches happen at loop boundaries.

That was my solution.

Yeh, but it isn’t restricted to the thread’s loop boundary. If getTheNextDataToProcess or noMoreDataIsComing do any looping, a context switch could also be triggered unless they use #Pragma DisableBackgroundTasks.

And that is about to change with preemptive threads with context switches at any time!

So we need methods such as, as it might be:

System.PreventPreemption ()
System.EnablePreemption ()

which could be applied to protect sequences of code.

As long as Xojo makes the CriticalSection and Semaphore classes work with preemptive threads then that functionality already exists.

1 Like