using System.Threading;
using System.Threading.Channels;
namespace Sandbox;
///
/// Utility functions that revolve around the main thread
///
public static class MainThread
{
static Channel Disposables = Channel.CreateUnbounded();
static Channel Actions = Channel.CreateUnbounded();
///
/// Wait to execute on the main thread
///
public static SyncTask Wait()
{
return new SyncTask( SyncContext.MainThread, allowSynchronous: true );
}
internal static void QueueDispose( IDisposable disposable )
{
if ( disposable is null )
return;
if ( ThreadSafe.IsMainThread )
{
disposable.Dispose();
return;
}
Disposables.Writer.TryWrite( disposable );
}
///
/// Run a function on the main thread and wait for the result.
///
internal static T Run( int millisecondsTimeout, Func func )
{
if ( ThreadSafe.IsMainThread )
return func();
T r = default;
ManualResetEvent reset = new ManualResetEvent( false );
Queue( () =>
{
try
{
r = func();
}
finally
{
reset.Set();
}
} );
if ( !reset.WaitOne( millisecondsTimeout ) )
{
return default;
}
return r;
}
internal static void RunQueues()
{
ThreadSafe.AssertIsMainThread();
while ( Disposables.Reader.TryRead( out var disposable ) )
{
disposable.Dispose();
}
RunMainThreadQueues();
}
///
/// When running in another thread you can queue a method to run in the main thread.
/// If you are on the main thread we will execute the method immediately and return.
///
public static void Queue( Action method )
{
if ( ThreadSafe.IsMainThread )
{
method();
return;
}
Actions.Writer.TryWrite( method );
}
///
/// Run queued actions on the main thread
///
internal static void RunMainThreadQueues()
{
ThreadSafe.AssertIsMainThread();
while ( Actions.Reader.TryRead( out var action ) )
{
try
{
action();
}
catch ( System.Exception e )
{
Log.Warning( e, e.Message );
}
}
}
}