Skip to content

Instantly share code, notes, and snippets.

@anonhostpi
Last active October 16, 2023 08:03
Show Gist options
  • Save anonhostpi/f9b3c65612cd5baea543a6b7da16c73e to your computer and use it in GitHub Desktop.
Save anonhostpi/f9b3c65612cd5baea543a6b7da16c73e to your computer and use it in GitHub Desktop.
How Avalonia Handles Multithreading

Preface:

This document serves at an attempt to reverse engineer, study, and simplify the usage and creation of Avalonia.Threading.Dispatcher. The goal of the document is to try to rewrite Avalonia.Threading.Dispatcher in such a way that it is not hardlinked to a UI Thread. This will expand its usability in other applications (like PowerShell threads) and allow the end user to associate a dispatcher with any thread they want.

My plan is to have the code used in avalonia eventually reimplemented as an extension to the System.Threading.Thread class. For now, I am mostly interested in reimplementing their dispatcher in PowerShell Core as an alternative to System.Windows.Threading.Dispatcher. That class is WPF-only and currently there is no fully cross-platform reimplementation of that class.

Avalonia is pretty close, but, again, it is hard associated with a UI and its thread; all I need to do is break that hard association.

A. Dispatcher and IDispatcher

The heart of Avalonia's multithreading

A.I. IDispatcher Interface

A.II. Dispatcher : IDispatcher Class

---TODOs---:

  • Check all References
    • Check all Extensions

A.I.a. Methods and Properties

  • _impl:

    • Type: private IDispatcherImpl
    • Description: Object containing all of the platform specific code to run the dispatcher
    • Set by: Constructor - Dispatcher(IDispatcher impl)
  • InstanceLock

    • Type: internal object
    • Description: The MutEx object used to lock the dispatcher
    • Locked and used by:
      • DispatcherOperation.cs
      • DispatcherFrame.cs
      • Dispatcher.Timer.cs
      • Dispatcher.Queue.cs
      • Dispatcher.MainLoop.cs
      • Dispatcher.Invoke.cs
  • _controlledImpl

    • Type: private IControlledDispatcherImpl?
    • Description: Used to add the RunLoop() method to a dispatcher via an IDispatcherImpl. This enables support for Dispatcher.PushFrame(), Dispatcher.MainLoop(), and DispatcherFrame.Run() that all require IDispatcherImpl.RunLoop()
  • s_uiThread

    • Type: private static Dispatcher?
    • Description: Singleton dispatcher that underlies the public UIThread property
    • Created by:
      • CreateUIThreadDispatcher()
      • UIThread - getter - Calls CreateUIThreadDispatcher(), if s_uiThread is null
  • _pendingInputImpl

    • Type: private IDispatcherImplWithPendingInput?
    • Description: Used to check if there is input pending. The dispatcher is written in such a way that it blocks execution of the dispatcher frames until input has been handled, even if the handler does not call anything on the UIThread. This allows for Input Events on the Avalonia Event Loop to have a chance to call the dispatcher before anything else, even if they don't need to.
    • Note: The actual handling of input and other events is happening on a separate loop and thread from the dispatcher+UIThread
  • _backgroundProcessingImpl

    • Type: private readonly IDispatcherImplWithExplicitBackgroundProcessing?
    • Description: Provides a platform-specific IDispatcherImpl.RequestBackgroundProcessing() method to be used in place of Dispatcher.RequestBackgroundProcessing()
  • _priorityContexts

    • Type: private readonly AvaloniaSynchronizationContext?[]
    • Declaration: new AvaloniaSynchronizationContext?[DispatcherPriority.MaxValue - DispatcherPriority.MinValue + 1]
  • Dispatcher(IDispatcher impl)

  • UIThread

    • Type: public static Dispatcher
    • Description: Public property "proxy" to s_uiThread. Ensures s_uiThread is created if it is null.
  • SupportsRunLoops

  • CreateUIThreadDispatcher()

  • CheckAccess()

  • VerifyAccess()

  • GetContextWithPriority(DispatcherPriority priority)

  • _queue (from Dispatcher.Queue.cs)

  • _signaled (from Dispatcher.Queue.cs)

  • _explicitBackgroundProcessingRequested (from Dispatcher.Queue.cs)

  • MaximumInputStarvationTimeInFallbackMode (from Dispatcher.Queue.cs)

  • MaximumInputStarvationTimeInExplicitProcessingExplicitMode (from Dispatcher.Queue.cs)

  • _maximumInputStarvationTime (from Dispatcher.Queue.cs)

  • RequestBackgroundProcessing() (from Dispatcher.Queue.cs)

  • OnReadyForExplicitBackgroundProcessing() (from Dispatcher.Queue.cs)

  • RunJobs(DispatcherPriority? priority = null) (from Dispatcher.Queue.cs)

  • RunJobs(DispatcherPriority? priority, CancellationToken cancellationToken) (from Dispatcher.Queue.cs)

B. IDispatcherImpl and Derivatives

These classes and objects contain the platform specific code to make their containing Dispatcher objects work on each platform

B.I. IDispatcherImpl Interface

B.II. IDispatcherImplWithPendingInput : IDispatcherImpl Interface

B.III. IDispatcherImplWithExplicitBackgroundProcessing : IDispatcherImpl Interface

B.IV. IControlledDispatcherImpl : IDispatcherImplWithPendingInput Interface

B.V. LegacyDispatcherImpl : IDispatcherImpl Class

B.VI. NullDispatcherImpl : IDispatcherImpl Class

B.VII. ManagedDispatcherImpl : IControlledDispatcherImpl Class

B.IV. Win32DispatcherImpl : IControlledDispatcherImpl Class

B.V. DispatcherImpl : IDispatcherImplWithExplicitBackgroundProcessing Class

B.VI. DispatcherImpl : IControlledDispatcherImpl, IDispatcherImplWithExplicitBackgroundProcessing Class

B.VII. X11PlatformThreading : IControlledDispatcherImpl Class

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment