结合应用域远程处理和任务时出现死锁 [英] Deadlock when combining app domain remoting and tasks

查看:25
本文介绍了结合应用域远程处理和任务时出现死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序需要将插件加载到单独的应用程序域中,然后异步执行其中的一些代码.我已经编写了一些代码来将 Task 包装在可编组类型中:

My app needs to load plugins into separate app domains and then execute some code inside of them asynchronously. I've written some code to wrap Task in marshallable types:

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 将永远不会返回.有什么想法吗?

But I've run into a snag. If you look in ClientComplete, there's a Task.Yield() I've inserted. If I comment this line, ClientComplete will never return. Any ideas?

推荐答案

我最好的猜测是您面临这些问题是因为 async 方法 包含 await 和这是通过 ThreadPool 管理的,它可以分配一些回收的线程.

My best guess is that you are facing these issues because of the async method that contains await and this is managed via the ThreadPool which can allocate some recycled Thread.

参考为所有服务器端代码调用 ConfigureAwait 的最佳做法

实际上,只需执行 await 就可以做到(将您置于不同的线程).一旦你的异步方法命中一个等待,该方法被阻塞但线程返回到线程水池.当方法准备好继续时,任何线程被抢夺来自线程池并用于恢复方法.

Actually, just doing an await can do that(put you on a different thread). Once your async method hits an await, the method is blocked but the thread returns to the thread pool. When the method is ready to continue, any thread is snatched from the thread pool and used to resume the method.

尝试精简代码,为基线案例生成线程并性能是最后的.

Try to streamline the code, generate threads for baseline cases and performance is last.

这篇关于结合应用域远程处理和任务时出现死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆