Shiny's picture

Processing window events in a separate thread

What is the best way to prevent actions such as window-dragging from blocking the main thread?
I'd like to keep synchronous access to window properties such as location and size.

I have a working solution, but it doesn't seem thread-safe.

My solution consists of two threads:

GUI Thread:

  • Creates a NativeWindow and registers event handlers to it. The event handlers do nothing more than queue the resulting events.
  • Calls NativeWindow.ProcessEvents() in a loop. The event handlers queue the results.
  • Does not interact with NativeWindow in any other way.

Main thread:

  • Creates the OpenGL context and attaches it to the NativeWindow.
  • Performs all program logic and rendering, including swapping framebuffers.
  • Does not directly use NativeWindow's events. Instead, the GUI thread's queued events are used.
  • Directly accesses NativeWindow's properties such as NativeWindow.Bounds and NativeWindow.WindowInfo.

The message queues get locked as needed, but the NativeWindow is never locked. Setting up locks on the NativeWindow only causes the GUI thread to freeze. I'm no expert on multithreading, so I've not found a solution to the latter.

This solution works now, but I worry that if the planets go out of alignment it could all come crashing down. Any ideas?


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Shiny's picture

Update:

I tried using GLControl within a WinForms Form.

This new method guarantees thread-safety because window properties can be retrieved synchronously (using Form.Invoke()).
But now the redraw / update rate plummets while resizing the window (as low as single digits).
So when resizing, the GLControl area lags behind the window too much for it to be usable.

By comparison, the method stated in the original post resizes very smoothly.

Shiny's picture

Another update:

The slowness was caused by Form.Invoke waiting on the GUI thread so much. Its use had to be minimized.

Now I'm caching certain window properties instead of calling Form.Invoke constantly.
This way Form.Invoke is only called when absolutely necessary and the main thread doesn't wait around so much.
And the window property cache is wrapped in a lock, so it's still thread-safe.

Problem solved?