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: