mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Add ITaskManager.BlockWaitOnTask()
Smugleaf needed this. Also changed RobustSynchronizationContext to use channels instead of ConcurrentQueue internally.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Shared.Exceptions;
|
||||
|
||||
namespace Robust.Shared.Asynchronous
|
||||
@@ -14,10 +15,19 @@ namespace Robust.Shared.Asynchronous
|
||||
public RobustSynchronizationContext(IRuntimeLog runtimeLog)
|
||||
{
|
||||
_runtimeLog = runtimeLog;
|
||||
|
||||
var channel = Channel.CreateUnbounded<Mail>(new UnboundedChannelOptions
|
||||
{
|
||||
SingleReader = true,
|
||||
SingleWriter = false
|
||||
});
|
||||
|
||||
_channelReader = channel.Reader;
|
||||
_channelWriter = channel.Writer;
|
||||
}
|
||||
|
||||
private readonly ConcurrentQueue<(SendOrPostCallback d, object? state)> _pending
|
||||
= new();
|
||||
private readonly ChannelReader<Mail> _channelReader;
|
||||
private readonly ChannelWriter<Mail> _channelWriter;
|
||||
|
||||
public override void Send(SendOrPostCallback d, object? state)
|
||||
{
|
||||
@@ -34,18 +44,18 @@ namespace Robust.Shared.Asynchronous
|
||||
|
||||
public override void Post(SendOrPostCallback d, object? state)
|
||||
{
|
||||
_pending.Enqueue((d, state));
|
||||
_channelWriter.TryWrite(new Mail(d, state));
|
||||
}
|
||||
|
||||
public void ProcessPendingTasks()
|
||||
{
|
||||
while (_pending.TryDequeue(out var task))
|
||||
while (_channelReader.TryRead(out var task))
|
||||
{
|
||||
#if EXCEPTION_TOLERANCE
|
||||
try
|
||||
#endif
|
||||
{
|
||||
task.d(task.state);
|
||||
task.Callback(task.State);
|
||||
}
|
||||
#if EXCEPTION_TOLERANCE
|
||||
catch (Exception e)
|
||||
@@ -55,5 +65,12 @@ namespace Robust.Shared.Asynchronous
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask<bool> WaitOnPendingTasks()
|
||||
{
|
||||
return _channelReader.WaitToReadAsync();
|
||||
}
|
||||
|
||||
private record struct Mail(SendOrPostCallback Callback, object? State);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Shared.Exceptions;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
@@ -32,10 +33,21 @@ namespace Robust.Shared.Asynchronous
|
||||
_mainThreadContext.Post(_runCallback, callback);
|
||||
}
|
||||
|
||||
private static readonly SendOrPostCallback _runCallback = o =>
|
||||
public void BlockWaitOnTask(Task task)
|
||||
{
|
||||
((Action?)o)?.Invoke();
|
||||
};
|
||||
// NOTE: This code should be re-entry safe.
|
||||
while (true)
|
||||
{
|
||||
var waitTask = _mainThreadContext.WaitOnPendingTasks().AsTask();
|
||||
var idx = Task.WaitAny(task, waitTask);
|
||||
if (idx == 0)
|
||||
return;
|
||||
|
||||
_mainThreadContext.ProcessPendingTasks();
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly SendOrPostCallback _runCallback = o => { ((Action?)o)?.Invoke(); };
|
||||
}
|
||||
|
||||
public interface ITaskManager
|
||||
@@ -52,5 +64,14 @@ namespace Robust.Shared.Asynchronous
|
||||
/// </remarks>
|
||||
/// <param name="callback">The callback that will be invoked on the main thread.</param>
|
||||
void RunOnMainThread(Action callback);
|
||||
|
||||
/// <summary>
|
||||
/// Synchronously wait for a main-thread task to complete.
|
||||
/// This is effectively what you need to safely .Result a task on the main thread.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use of this method is only ever recommended in rare scenarios like shutdown. For most other scenarios you should really avoid blocking the main thread and use proper async instead.
|
||||
/// </remarks>
|
||||
void BlockWaitOnTask(Task task);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user