Preemptive thread weird behaviour with DoEvents and Thread.Sleep

I have had an issue with my 2024r2.1 desktop application that has the main thread hanging randomly while all the threads still work just fine. (Linux desktop app main thread frozen, other threads still executing) With the large changes around threading in 2024r3.1 I thought I would give it a go to see it if fixed my issue.

While I didn’t initially need to change my program to use preemptive threads, I did want to play around with them. For part of one of my apps, I am trying to get consistent cycle times for processing math calculations at a regular interval. I built a test console app to compare event loop (DoEvents), timer, co-op and preemptive threads with both normal (5) and high priority (50).

My first issue is that using Thread.Sleep(10) in a preemptive thread caused the program to crash.

libc++abi: terminating due to uncaught exception of type std::__1::system_error: mutex lock failed: Invalid argument
[1]    54023 abort

I did see some reports about Thread.Sleep in preemptive threads so I left it there and continued on without sleeping the preemptive threads. This brought some even more weird behaviour.

First test was in the debugger, I noticed that preemptive threads cause Thread.Sleep and DoEvents to finish early most of the time.

This is in microseconds, target was 10,000us.

Iteration Event Loop Timer Coop Thread Hi-Pri Coop Thread Preemptive Thread Hi-Pri Preemptive Thread
1 86.875 15624.042 4.875 4.583 0.208 97.792
2 372.292 12379.875 10081.875 22.042 0.250 0.250
3 108.958 15890.000 10652.500 50.333 0.208 0.250
4 9284.000 12791.750 37.167 2.667 0.250 207.583
5 8478.833 14810.125 110.750 17.167 0.250 46.917
6 140.542 12501.750 37.042 4.292 0.208 0.250
7 939.167 15985.333 10.875 42.958 0.250 0.208
8 137.333 13139.958 32.083 10380.542 0.250 0.208
9 35.042 15047.500 48.750 10075.500 0.250 288.167
10 162.375 13453.500 39.583 24.500 0.250 350.958

I then ran it as a built app and the behaviour changed, now the co-op threads are fairly consistent, however, DoEvents(10) finished early every time.

Iteration Event Loop Timer Coop Thread Hi-Pri Coop Thread Preemptive Thread Hi-Pri Preemptive Thread
1 19.083 10956.958 10598.625 10603.708 0.042 0.042
2 17.458 20549.667 10358.125 10355.750 0.042 0.000
3 12.458 10580.667 9434.208 9427.167 0.000 0.042
4 12.167 20084.833 11508.583 11320.125 0.000 0.042
5 19.708 10801.708 10656.292 10825.667 0.042 0.042
6 13.083 20842.125 11321.375 11315.708 0.042 0.042
7 12.417 12486.833 11277.250 11255.292 0.042 0.042
8 12.000 19754.875 9956.875 9955.083 0.042 0.042
9 11.708 10749.292 9502.125 9500.208 0.042 0.000
10 11.625 20827.083 10174.792 10175.833 0.042 0.042

This is all kinda weird and I haven’t dug in enough as I have been battling my hanging issue. Am I doing something wrong here or is this behaviour that anyone else has been observing? Please see my test app attached (I can cause the crash by uncommenting sender.Sleep(10) in a preemptive thread)

Thread Consistency.xojo_binary_project.zip (3.4 KB)

DoEvents is not for Desktop Apps. Stop using it.

7 Likes

Yeah, don’t do this. You’re having one thread alter are state of another and will pretty much guarantee a crash.

You’ll have the best success by making preemptive thread code as isolated as possible and not sharing access or cross-calling anything that could cause things to be modified at the same time. A good rule of thumb for Sleep is to only call it as Self.Sleep.

1 Like

Yes, a thread should only sleep itself.

1 Like

This is not for desktop.

Thanks, this was only a console app, thats the last thing I would want to do in a desktop app.

Yes, this is also something I would not do, “sender” is it’s self in this case (AddHandler)

I saw a report about the DoEvents finishing early somewhere in the forum. So it’s a known issue. Possibly fixed in r4 (if memory serves)

Thanks, looks like its related to Thread.Sleep when the debugger is used.