当应用程序域远程和任务相结合时死锁
本文关键字:相结合 死锁 任务 应用程序域 | 更新日期: 2023-09-27 18:01:41
我的应用程序需要加载插件到单独的应用程序域,然后异步执行其中的一些代码。我已经编写了一些代码将Task
包装为可编组类型:
static class RemoteTask
{
public static async Task<T> ClientComplete<T>(RemoteTask<T> remoteTask,
CancellationToken cancellationToken)
{
T result;
using (cancellationToken.Register(remoteTask.Cancel))
{
RemoteTaskCompletionSource<T> tcs = new RemoteTaskCompletionSource<T>();
remoteTask.Complete(tcs);
result = await tcs.Task;
}
await Task.Yield(); // HACK!!
return result;
}
public static RemoteTask<T> ServerStart<T>(Func<CancellationToken, Task<T>> func)
{
return new RemoteTask<T>(func);
}
}
class RemoteTask<T> : MarshalByRefObject
{
readonly CancellationTokenSource cts = new CancellationTokenSource();
readonly Task<T> task;
internal RemoteTask(Func<CancellationToken, Task<T>> starter)
{
this.task = starter(cts.Token);
}
internal void Complete(RemoteTaskCompletionSource<T> tcs)
{
task.ContinueWith(t =>
{
if (t.IsFaulted)
{
tcs.TrySetException(t.Exception);
}
else if (t.IsCanceled)
{
tcs.TrySetCancelled();
}
else
{
tcs.TrySetResult(t.Result);
}
}, TaskContinuationOptions.ExecuteSynchronously);
}
internal void Cancel()
{
cts.Cancel();
}
}
class RemoteTaskCompletionSource<T> : MarshalByRefObject
{
readonly TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
public bool TrySetResult(T result) { return tcs.TrySetResult(result); }
public bool TrySetCancelled() { return tcs.TrySetCanceled(); }
public bool TrySetException(Exception ex) { return tcs.TrySetException(ex); }
public Task<T> Task
{
get
{
return tcs.Task;
}
}
}
它的用法如下:
sealed class ControllerAppDomain
{
PluginAppDomain plugin;
public Task<int> SomethingAsync()
{
return RemoteTask.ClientComplete(plugin.SomethingAsync(), CancellationToken.None);
}
}
sealed class PluginAppDomain : MarshalByRefObject
{
public RemoteTask<int> SomethingAsync()
{
return RemoteTask.ServerStart(async cts =>
{
cts.ThrowIfCancellationRequested();
return 1;
});
}
}
但是我遇到了一个障碍。如果你看ClientComplete
,我插入了一个Task.Yield()
。如果我注释这一行,ClientComplete
将永远不会返回。什么好主意吗?
我最好的猜测是你正面临这些问题,因为async方法包含await,这是通过ThreadPool管理的,它可以分配一些回收线程。
参考对所有服务器端代码调用ConfigureAwait的最佳实践
实际上,只是做一个等待可以做到这一点(把你放在一个不同的线程)。一旦async方法命中在await中,方法被阻塞,但是线程返回到线程池。当方法准备好继续执行时,任何线程都将被抓取从线程池中取出并用于恢复该方法。
尝试简化代码,为基线情况生成线程和