Hide scheduler from RunOnFrameworkThread (#1725)

* Hide scheduler from RunOnFrameworkThread

Creating new tasks via Task.Run and alike would fetch the current
scheduler, which we do not want in case of running stuff from the
framework thread. Change is to prevent the standard library from seeing
the "current scheduler". If one wants to use `await` with an async
function to be run in the framework thread, one can use
`RunOnFrameworkThreadAwaitable` instead now.

* TaskSchedulerWidget: test better stuff

* TaskSchedulerWidget: add freeze tests

* More comments

* Make TaskFactory a getter method instead of property to avoid bad suggestions

* Why are there stuff still not pushed
This commit is contained in:
srkizer 2024-03-19 12:10:47 +09:00 committed by GitHub
parent c709ad1811
commit 5d473919a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 310 additions and 22 deletions

View file

@ -144,9 +144,7 @@ internal class TaskSchedulerWidget : IDataWindowWidget
_ = framework.RunOnTick(() => Log.Information("Framework.Update - In 2s+60f"), cancellationToken: this.taskSchedulerCancelSource.Token, delay: TimeSpan.FromSeconds(2), delayTicks: 60);
}
ImGui.SameLine();
if (ImGui.Button("Every 60 frames"))
if (ImGui.Button("Every 60f"))
{
_ = framework.RunOnTick(
async () =>
@ -154,6 +152,8 @@ internal class TaskSchedulerWidget : IDataWindowWidget
for (var i = 0L; ; i++)
{
Log.Information($"Loop #{i}; MainThread={ThreadSafety.IsMainThread}");
var it = i;
_ = Task.Factory.StartNew(() => Log.Information($" => Sub #{it}; MainThread={ThreadSafety.IsMainThread}"));
await framework.DelayTicks(60, this.taskSchedulerCancelSource.Token);
}
},
@ -162,6 +162,68 @@ internal class TaskSchedulerWidget : IDataWindowWidget
ImGui.SameLine();
if (ImGui.Button("Every 1s"))
{
_ = framework.RunOnTick(
async () =>
{
for (var i = 0L; ; i++)
{
Log.Information($"Loop #{i}; MainThread={ThreadSafety.IsMainThread}");
var it = i;
_ = Task.Factory.StartNew(() => Log.Information($" => Sub #{it}; MainThread={ThreadSafety.IsMainThread}"));
await Task.Delay(TimeSpan.FromSeconds(1), this.taskSchedulerCancelSource.Token);
}
},
cancellationToken: this.taskSchedulerCancelSource.Token);
}
ImGui.SameLine();
if (ImGui.Button("Every 60f (Await)"))
{
_ = framework.RunOnFrameworkThreadAwaitable(
async () =>
{
for (var i = 0L; ; i++)
{
Log.Information($"Loop #{i}; MainThread={ThreadSafety.IsMainThread}");
var it = i;
_ = Task.Factory.StartNew(() => Log.Information($" => Sub #{it}; MainThread={ThreadSafety.IsMainThread}"));
await framework.DelayTicks(60, this.taskSchedulerCancelSource.Token);
}
},
this.taskSchedulerCancelSource.Token);
}
ImGui.SameLine();
if (ImGui.Button("Every 1s (Await)"))
{
_ = framework.RunOnFrameworkThreadAwaitable(
async () =>
{
for (var i = 0L; ; i++)
{
Log.Information($"Loop #{i}; MainThread={ThreadSafety.IsMainThread}");
var it = i;
_ = Task.Factory.StartNew(() => Log.Information($" => Sub #{it}; MainThread={ThreadSafety.IsMainThread}"));
await Task.Delay(TimeSpan.FromSeconds(1), this.taskSchedulerCancelSource.Token);
}
},
this.taskSchedulerCancelSource.Token);
}
ImGui.SameLine();
if (ImGui.Button("As long as it's in Framework Thread"))
{
Task.Run(async () => await framework.RunOnFrameworkThread(() => { Log.Information("Task dispatched from non-framework.update thread"); }));
framework.RunOnFrameworkThread(() => { Log.Information("Task dispatched from framework.update thread"); }).Wait();
}
ImGui.SameLine();
if (ImGui.Button("Error in 1s"))
{
_ = framework.RunOnTick(() => throw new Exception("Test Exception"), cancellationToken: this.taskSchedulerCancelSource.Token, delay: TimeSpan.FromSeconds(1));
@ -169,10 +231,18 @@ internal class TaskSchedulerWidget : IDataWindowWidget
ImGui.SameLine();
if (ImGui.Button("As long as it's in Framework Thread"))
if (ImGui.Button("Freeze 1s"))
{
Task.Run(async () => await framework.RunOnFrameworkThread(() => { Log.Information("Task dispatched from non-framework.update thread"); }));
framework.RunOnFrameworkThread(() => { Log.Information("Task dispatched from framework.update thread"); }).Wait();
_ = framework.RunOnFrameworkThread(() => Helper().Wait());
static async Task Helper() => await Task.Delay(1000);
}
ImGui.SameLine();
if (ImGui.Button("Freeze Completely"))
{
_ = framework.RunOnFrameworkThreadAwaitable(() => Helper().Wait());
static async Task Helper() => await Task.Delay(1000);
}
if (ImGui.CollapsingHeader("Download"))
@ -217,7 +287,7 @@ internal class TaskSchedulerWidget : IDataWindowWidget
this.downloadState = default;
var factory = downloadUsingGlobalScheduler
? Task.Factory
: framework.FrameworkThreadTaskFactory;
: framework.GetTaskFactory();
this.downloadState = default;
this.downloadTask = factory.StartNew(
async () =>