组合应用程序域远程和任务时死锁 [英] Deadlock when combining app domain remoting and tasks

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

问题描述

我的应用程序需要的插件加载到单独的应用程序域,然后执行一些代码其中的内部异步。我已经写了一些代码来包装任务在marshallable类型:

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;
        }
    }
}



它的使用,如:

It's used like:

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?

推荐答案

我最好的猜测是,你所面临的这些问题,是因为在异步方法包含的await ,这是通过线程池可分配一些回收螺纹

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可以做到这一点(让你在不同的线程)。一旦异步方法命中
。将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天全站免登陆