提交 fadea7df 编写于 作者: K Kevin Halverson

Avoid async deadlock in InteractiveHost...

The scheduler returned by TaskScheduler.FromCurrentSynchronizationContext
does not allow concurrency (meaning all Tasks within a submission were being
inlined).  This would nearly always result in a deadlock if you kicked off a
child Task and attempted to continue within the same submission.

We can instead use the Winforms Dispatcher, which will invoke the parent
Task on the "UI" thread but allow child Tasks to use the ThreadPool.
上级 2d4523b2
......@@ -36,7 +36,7 @@ internal sealed class Service : MarshalByRefObject, IDisposable
{
private static readonly ManualResetEventSlim s_clientExited = new ManualResetEventSlim(false);
private static TaskScheduler s_UIThreadScheduler;
private static Control s_control;
private InteractiveAssemblyLoader _assemblyLoader;
private MetadataShadowCopyProvider _metadataFileProvider;
......@@ -256,9 +256,8 @@ private static void RunServer(string serverPort, string semaphoreName, int clien
{
var uiThread = new Thread(() =>
{
var c = new Control();
c.CreateControl();
s_UIThreadScheduler = TaskScheduler.FromCurrentSynchronizationContext();
s_control = new Control();
s_control.CreateControl();
resetEvent.Set();
Application.Run();
});
......@@ -815,15 +814,14 @@ private static void DisplaySearchPaths(TextWriter writer, List<string> attempted
private async Task<ScriptState<object>> ExecuteOnUIThread(Script<object> script, ScriptState<object> stateOpt)
{
return await Task.Factory.StartNew(async () =>
return await ((Task<ScriptState<object>>)s_control.Invoke(
(Func<Task<ScriptState<object>>>)(() =>
{
try
{
var task = (stateOpt == null) ?
return (stateOpt == null) ?
script.RunAsync(_globals, CancellationToken.None) :
script.ContinueAsync(stateOpt, CancellationToken.None);
return await task.ConfigureAwait(false);
}
catch (FileLoadException e) when (e.InnerException is InteractiveAssemblyLoaderException)
{
......@@ -836,10 +834,7 @@ private async Task<ScriptState<object>> ExecuteOnUIThread(Script<object> script,
Console.Error.WriteLine(e);
return null;
}
},
CancellationToken.None,
TaskCreationOptions.None,
s_UIThreadScheduler).Unwrap().ConfigureAwait(false);
}))).ConfigureAwait(false);
}
private void DisplayInteractiveErrors(ImmutableArray<Diagnostic> diagnostics, TextWriter output)
......
......@@ -1123,6 +1123,23 @@ public class C
AssertEx.AssertEqualToleratingWhitespaceDifferences("C { P=null }", output);
}
[Fact, WorkItem(7280, "https://github.com/dotnet/roslyn/issues/7280")]
public void AsyncContinueOnDifferentThread()
{
Execute(@"
using System;
using System.Threading;
using System.Threading.Tasks;
Console.Write(Task.Run(() => { Thread.CurrentThread.Join(100); return 42; }).ContinueWith(t => t.Result).Result)");
var output = ReadOutputToEnd();
var error = ReadErrorOutputToEnd();
Assert.Equal("42", output);
Assert.Empty(error);
}
#region Submission result printing - null/void/value.
[Fact]
......
......@@ -443,7 +443,7 @@ internal new Task<ScriptState<T>> ContinueAsync(ScriptState previousState, Cance
private async Task<ScriptState<T>> RunSubmissionsAsync(ScriptExecutionState executionState, ImmutableArray<Func<object[], Task>> precedingExecutors, Func<object[], Task> currentExecutor, CancellationToken cancellationToken)
{
var result = await executionState.RunSubmissionsAsync<T>(precedingExecutors, currentExecutor, cancellationToken).ConfigureAwait(continueOnCapturedContext: true);
var result = await executionState.RunSubmissionsAsync<T>(precedingExecutors, currentExecutor, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
return new ScriptState<T>(executionState, result, this);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册