Browse Source

Merge pull request #6527 from workgroupengineering/features/Core/Threading/Dispatcher/Post_Overload

Features Dispatcher.Post<T>(Action<T>, T arg, DispatcherPriority priority = DispatcherPriority.Normal)
pull/7285/head
Max Katz 5 years ago
committed by GitHub
parent
commit
defbf2543e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      src/Avalonia.Base/ApiCompatBaseline.txt
  2. 9
      src/Avalonia.Base/Threading/Dispatcher.cs
  3. 9
      src/Avalonia.Base/Threading/IDispatcher.cs
  4. 83
      src/Avalonia.Base/Threading/JobRunner.cs
  5. 6
      tests/Avalonia.UnitTests/ImmediateDispatcher.cs

3
src/Avalonia.Base/ApiCompatBaseline.txt

@ -0,0 +1,3 @@
Compat issues with assembly Avalonia.Base:
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Threading.IDispatcher.Post<T>(System.Action<T>, T, Avalonia.Threading.DispatcherPriority)' is present in the implementation but not in the contract.
Total Issues: 1

9
src/Avalonia.Base/Threading/Dispatcher.cs

@ -81,7 +81,7 @@ namespace Avalonia.Threading
_ = action ?? throw new ArgumentNullException(nameof(action));
return _jobRunner.InvokeAsync(action, priority);
}
/// <inheritdoc/>
public Task<TResult> InvokeAsync<TResult>(Func<TResult> function, DispatcherPriority priority = DispatcherPriority.Normal)
{
@ -110,6 +110,13 @@ namespace Avalonia.Threading
_jobRunner.Post(action, priority);
}
/// <inheritdoc/>
public void Post<T>(Action<T> action, T arg, DispatcherPriority priority = DispatcherPriority.Normal)
{
_ = action ?? throw new ArgumentNullException(nameof(action));
_jobRunner.Post(action, arg, priority);
}
/// <summary>
/// This is needed for platform backends that don't have internal priority system (e. g. win32)
/// To ensure that there are no jobs with higher priority

9
src/Avalonia.Base/Threading/IDispatcher.cs

@ -26,6 +26,15 @@ namespace Avalonia.Threading
/// <param name="priority">The priority with which to invoke the method.</param>
void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal);
/// <summary>
/// Posts an action that will be invoked on the dispatcher thread.
/// </summary>
/// <typeparam name="T">type of argument</typeparam>
/// <param name="action">The method to call.</param>
/// <param name="arg">The argument of method to call.</param>
/// <param name="priority">The priority with which to invoke the method.</param>
void Post<T>(Action<T> action, T arg, DispatcherPriority priority = DispatcherPriority.Normal);
/// <summary>
/// Invokes a action on the dispatcher thread.
/// </summary>

83
src/Avalonia.Base/Threading/JobRunner.cs

@ -13,7 +13,7 @@ namespace Avalonia.Threading
{
private IPlatformThreadingInterface? _platform;
private readonly Queue<IJob>[] _queues = Enumerable.Range(0, (int) DispatcherPriority.MaxValue + 1)
private readonly Queue<IJob>[] _queues = Enumerable.Range(0, (int)DispatcherPriority.MaxValue + 1)
.Select(_ => new Queue<IJob>()).ToArray();
public JobRunner(IPlatformThreadingInterface? platform)
@ -59,7 +59,7 @@ namespace Avalonia.Threading
/// <returns>A task that can be used to track the method's execution.</returns>
public Task<TResult> InvokeAsync<TResult>(Func<TResult> function, DispatcherPriority priority)
{
var job = new Job<TResult>(function, priority);
var job = new JobWithResult<TResult>(function, priority);
AddJob(job);
return job.Task;
}
@ -75,6 +75,17 @@ namespace Avalonia.Threading
AddJob(new Job(action, priority, true));
}
/// <summary>
/// Post action that will be invoked on main thread
/// </summary>
/// <param name="action">The method to call.</param>
/// <param name="parameter">The parameter of method to call.</param>
/// <param name="priority">The priority with which to invoke the method.</param>
internal void Post<T>(Action<T> action, T parameter, DispatcherPriority priority)
{
AddJob(new Job<T>(action, parameter, priority, true));
}
/// <summary>
/// Allows unit tests to change the platform threading interface.
/// </summary>
@ -86,7 +97,7 @@ namespace Avalonia.Threading
private void AddJob(IJob job)
{
bool needWake;
var queue = _queues[(int) job.Priority];
var queue = _queues[(int)job.Priority];
lock (queue)
{
needWake = queue.Count == 0;
@ -98,7 +109,7 @@ namespace Avalonia.Threading
private IJob? GetNextJob(DispatcherPriority minimumPriority)
{
for (int c = (int) DispatcherPriority.MaxValue; c >= (int) minimumPriority; c--)
for (int c = (int)DispatcherPriority.MaxValue; c >= (int)minimumPriority; c--)
{
var q = _queues[c];
lock (q)
@ -109,14 +120,14 @@ namespace Avalonia.Threading
}
return null;
}
private interface IJob
{
/// <summary>
/// Gets the job priority.
/// </summary>
DispatcherPriority Priority { get; }
/// <summary>
/// Runs the job.
/// </summary>
@ -177,11 +188,61 @@ namespace Avalonia.Threading
}
}
}
/// <summary>
/// A job to run.
/// A typed job to run.
/// </summary>
/// <typeparam name="T">Type of job parameter</typeparam>
private sealed class Job<T> : IJob
{
private readonly Action<T> _action;
private readonly T _parameter;
private readonly TaskCompletionSource<bool>? _taskCompletionSource;
/// <summary>
/// Initializes a new instance of the <see cref="Job"/> class.
/// </summary>
/// <param name="action">The method to call.</param>
/// <param name="parameter">The parameter of method to call.</param>
/// <param name="priority">The job priority.</param>
/// <param name="throwOnUiThread">Do not wrap exception in TaskCompletionSource</param>
public Job(Action<T> action, T parameter, DispatcherPriority priority, bool throwOnUiThread)
{
_action = action;
_parameter = parameter;
Priority = priority;
_taskCompletionSource = throwOnUiThread ? null : new TaskCompletionSource<bool>();
}
/// <inheritdoc/>
public DispatcherPriority Priority { get; }
/// <inheritdoc/>
void IJob.Run()
{
if (_taskCompletionSource == null)
{
_action(_parameter);
return;
}
try
{
_action(_parameter);
_taskCompletionSource.SetResult(default);
}
catch (Exception e)
{
_taskCompletionSource.SetException(e);
}
}
}
/// <summary>
/// A job to run thath return value.
/// </summary>
private sealed class Job<TResult> : IJob
/// <typeparam name="TResult">Type of job result</typeparam>
private sealed class JobWithResult<TResult> : IJob
{
private readonly Func<TResult> _function;
private readonly TaskCompletionSource<TResult> _taskCompletionSource;
@ -191,7 +252,7 @@ namespace Avalonia.Threading
/// </summary>
/// <param name="function">The method to call.</param>
/// <param name="priority">The job priority.</param>
public Job(Func<TResult> function, DispatcherPriority priority)
public JobWithResult(Func<TResult> function, DispatcherPriority priority)
{
_function = function;
Priority = priority;
@ -200,7 +261,7 @@ namespace Avalonia.Threading
/// <inheritdoc/>
public DispatcherPriority Priority { get; }
/// <summary>
/// The task.
/// </summary>

6
tests/Avalonia.UnitTests/ImmediateDispatcher.cs

@ -21,6 +21,12 @@ namespace Avalonia.UnitTests
action();
}
/// <inheritdoc/>
public void Post<T>(Action<T> action, T arg, DispatcherPriority priority = DispatcherPriority.Normal)
{
action(arg);
}
/// <inheritdoc/>
public Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
{

Loading…
Cancel
Save