Preemptive Thread Issues on Windows - Multiple Threads

I am seeing some pretty serious crashes with preemptive threads in windows. I have multiple copies of my thread running all in different instances of the same object. Things run fine for a while but eventually I get a runtime error. It happens when I am drawing a picture in both the main thread and in running thread at the same time. But the picture objects are from different instances. Seems like there’s corruption between instances in Windows. Yes, everything is semaphored, but since it’s different instances, the semaphores don’t come into play.

Anyhow, here’s my crash report link:
https://tracker.xojo.com/xojoinc/xojo/-/issues/77761#note_586575

It’s similar to another report with the same issue. In that issue @Rick_Araujo attached an example project showing how to “properly” handle the issue the user was describing. I have taken Rick’s example, and added 5 more instances of the same canvas and thread. In MacOS I can run everything just fine. In windows, as soon as you add the second thread, it crashes. I don’t get the runtime error, it just crashes.

This is pretty significant…

1 Like

FYI - William Yu has confirmed this.

William confirmed a crash. Your design is completely different of the simple code I’ve fixed, and you are playing with contents intended to be used on UI from a thread, using drawing routines from such thread, that at some extents it is forbidden, unless completely detached from any UI. I guess William found that you intended to do an off-screen drawing, maybe valid, but some framework assertion was fired as if it was targeting the UI from a background thread and it crashed. Not really a concurrency problem at this point. We really need William inspection (and maybe a fix) of your case on the R4 cycle.

Rick - There is no drawing from a thread. All I did was take your example and make multiple copies of it in the same app. I did not touch your thread code or the code in the canvas. All I did was create a control set of canvases and an array of threads. I added each thread as a property of the canvas.

I don’t think you took much time to look at what I did. I spent less than 10 minutes on this. It is absolutely drawing the exact same way as yours did. If you have a single thread running it works just fine - just like your example. It’s when you add a second thread that windows freaks out. So I think you are rushing to judgement here.

If I did as you claim, please point to where I am doing it. Back it up, please.

From your thread, you’ve created a rectangle:

OffscreenPicture = New Picture(Width, Height)
OffscreenPicture.Graphics.DrawingColor = Color.RGB(Rnd * 255, Rnd * 255, Rnd * 255)
OffscreenPicture.Graphics.FillRectangle(Rnd * OffscreenPicture.Width, _
Rnd * OffscreenPicture.Height, Rnd * 50, Rnd * 50)

And the framework:

Failed assertion at DrawableD2D.cpp:534

Message: CreateBitmapFromWicBitmap failed: 88982f0d

Uh friend, that is your code. Not mine. And yes, it’s a rectangle. You can draw into graphics contexts of pictures in threads. You can’t draw into UI controls.

I’m using YOUR code, so please don’t throw stones at me.

Please, show me the case with my code. I’ll check the difference.

And no, I’m not throwing stones, please. Just looking what’s going on with the case you reported.

Here’s a screenshot of your project with your code:

And here’s the code:

Sub Run() Handles Run
  // Using the current design intent, Create a CriticalSection to control the access to OffscreenPicture
  CritSectOffScrPicture = New CriticalSection
  CritSectOffScrPicture.Type = Thread.Types.Preemptive
  
  CritSectOffScrPicture.Enter // let's touch OffscreenPicture
  
  // create a new picture to draw the pixels into
  OffscreenPicture = New Picture(Width, Height)
  
  CritSectOffScrPicture.Leave  // Release it to anyone else
  
  Do
    CritSectOffScrPicture.Enter   // let's touch OffscreenPicture
    
    // draw a random colorered pixel into a random spot in the offscreen picture
    OffscreenPicture.Graphics.DrawingColor = Color.RGB(Rnd * 255, Rnd * 255, Rnd * 255)
    OffscreenPicture.Graphics.FillRectangle(Rnd * OffscreenPicture.Width, _
    Rnd * OffscreenPicture.Height, Rnd * 50, Rnd * 50)
    //me.sleep(1)
    
    CritSectOffScrPicture.Leave   // Release it to anyone else
    
  Loop Until Stop // the Stop property of the thread is set by the Stop button in the window
End Sub

And as I have been saying, running a single or multiple threads in MacOS works great. No issues.

Running a single thread in Windows works great. No issues.

Attempting to run a second thread in Windows results in the crash.

I did not touch your thread code one bit. It’s exactly as you wrote it.

I’ll try to locate the file, and will download the 2024r3.1 again to observe both apps.

Edit: found it. in this thread:

https://forum.xojo.com/t/preemptive-threads-draw-operations-thread-safe/81615/1

Now will download 2024r3.1 to see what you see. :wink:

I don’t have much time, so it will be done gradually.

First part is: What you called “my app”, was just someone else’s sample that was crashing, and I just fixed what was broken. No enough clean ups, not exactly well done, just fixed.

So I got my take on that thread, refactored a bit, and here is my version (made right now, I hope I’ve cleaned it enough):

DrawThread-Rick.zip (7.6 KB)

Later I’ll will check your code, that I see that it has a “semantics approach I prefer differently”

And we will see what I get. :wink:

Thanks, Rick.

Your changes make the BackgroundDrawing object more elegant. But they don’t fundamentally change what the thread is doing or how it is doing it.

I have a further update as well. Given the challenges I was having with the Listbox control (you’ve been involved in that thread here on the forums as well), I wanted to see if I could create an example project to duplicate that problem. So I decided to add a listbox to this project and effectively attempt to recreate a situation similar to what my app is doing.

I’ve added a listbox that has three columns. Column 0 contains just plain text. The other two are columns that get updated by the PaintCellTextEvent. When I add a new canvas and thread, I add a row to the listbox, set the “name” in column 0 and then add the canvas as the RowTag of the listbox.

I then have a timer that creates a random number and sets it as a property of the canvas. I then call the PaintCellText event for each row of the Listbox. In the PaintCellText Event of the listbox, I reference the canvas, grab the value of the property and paint it into Column 1. I then draw a graphic in Column 3 depending on whether the number is even or odd.

On Mac this runs fine. Unfortunately, I was not able to get it to crash as I had hoped.

In WIndows, this version crashes immediately.

Again, NOTHING in what I am doing touches any of the thread code or objects in the thread. If you (or anyone else) can see where I am doing this and violating a rule - please show me.

In the link below is a movie of how things work on the Mac and how things work in Windows (tried attaching it as a ZIP file but the editor is throwing an error here - maybe too large).

Attached is the project. Again, show me where I am doing something like touching the UI portion of the control from the thread. I’m not…
DrawThread.xojo_binary_project.zip (13.0 KB)

Furthermore, I just decided to see what happens in Windows if I don’t even paint the picture generated by the thread to the canvas. I’ve commented out the code in the paint event of the canvas. Still get a crash.

In reality, it does, the previous one was prone to crashes under certain circunstancies. The current one probably is slightly faster too.

You see, small details, hard to see, may be the difference between something working great and not working at all.

Broken. Include the missing parts.

Edit: I’ll make my own

That’s weird. Sure.

DrawThreadExample.zip (66.1 KB)

What is the difference other than syntactical ones? You’ve moved the critical section calls to methods in the thread. You added a constructor method.

The picture object is created in the main thread (constructor) instead of in the thread itself. The algorithm that is running in the loop in the thread is the same thing. I really fail to see how those changes make it faster or more stable.

Also, I’ve had the latest version of the app running on my Mac for two hours and it’s still running fine. If I was accessing UI objects from the thread or not properly accessing objects, it would have crashed. OS X does not like it if you attempt to manipulate the UI from the thread.

Windows - it just crashed immediately.

Well, William just updated my case. There is absolutely a problem in Windows with threads drawing pictures concurrently:

Additionally, we don’t currently support concurrent drawing of Pictures on separate threads on Windows (we may be able to in the future but this greatly impacts drawing speed), so you’ll need to handle locking and unlocking at the app level to ensure only one thread is drawing on its Picture at a time.

So if you want to do picture drawing in multiple threads, you will need to have an app level lock that controls this. That’s a big drawback in my mind as the whole purpose of preemptive threading is to be able to do concurrent actions…

Hi @Jon_Ogden ,

Not meaning to Hijack the thread. Thank you for persisting on working with debugging Preemptive threads. I am watching in the background as to how successful this is.

I’ll retreat from the thread now. :slight_smile: