@ -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>
@ -157,7 +168,7 @@ namespace Avalonia.Threading
/// The task.
/// </summary>
public Task Task = > _ taskCompletionSource ? . Task ;
/// <inheritdoc/>
void IJob . Run ( )
{
@ -177,11 +188,60 @@ namespace Avalonia.Threading
}
}
}
/// <summary>
/// A job to run.
/// A tipizzed job to run.
/// </summary>
private sealed class Job < TResult > : IJob
private sealed class Job < T > : IJob
{
private readonly Action < T > _ action ;
private readonly T _ parameter ;
private readonly TaskCompletionSource < object > _ 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 < object > ( ) ;
}
/// <inheritdoc/>
public DispatcherPriority Priority { get ; }
/// <inheritdoc/>
void IJob . Run ( )
{
if ( _ taskCompletionSource = = null )
{
_ action ( _ parameter ) ;
return ;
}
try
{
_ action ( _ parameter ) ;
_ taskCompletionSource . SetResult ( null ) ;
}
catch ( Exception e )
{
_ taskCompletionSource . SetException ( e ) ;
}
}
}
/// <summary>
/// A job to run thath return value.
/// </summary>
private sealed class JobWithResult < TResult > : IJob
{
private readonly Func < TResult > _f unction ;
private readonly TaskCompletionSource < TResult > _ taskCompletionSource ;
@ -191,7 +251,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 )
{
_f unction = function ;
Priority = priority ;
@ -200,7 +260,7 @@ namespace Avalonia.Threading
/// <inheritdoc/>
public DispatcherPriority Priority { get ; }
/// <summary>
/// The task.
/// </summary>