如何跨 AppDomain 边界传递 CancellationToken? [英] How do I pass CancellationToken across AppDomain boundary?

查看:25
本文介绍了如何跨 AppDomain 边界传递 CancellationToken?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个命令对象,它根据来自请求队列的请求执行工作.此特定命令将在子应用程序域中执行其工作.在子应用程序域中执行其工作的一部分涉及阻塞 ConcurrentQueue 操作(例如,添加或获取).我需要能够通过请求队列将中止信号传播到子应用程序域,并唤醒其中的工作线程.

I have a command object, doing work based on a request from a request queue. This particular command will execute its work in a child appdomain. Part of doing its work in the child appdomain involves blocking on a ConcurrentQueue operation (eg, Add or Take). I need to be able to propagate an abort signal through the request queue, across to the child appdomain, and to wake up the worker threads therein.

因此,我认为我需要跨 AppDomain 边界传递一个 CancellationToken.

Therefore, I think I need to pass a CancellationToken across the AppDomain boundary.

我尝试创建一个继承自 MarshalByRefObject 的类:

I tried creating a class which inherits from MarshalByRefObject:

protected class InterAppDomainAbort : MarshalByRefObject, IAbortControl
    {
        public InterAppDomainAbort(CancellationToken t)
        {
            Token = t;
        }

        [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
        public override object InitializeLifetimeService()
        {
            return null;
        }

        public CancellationToken Token
        {
            get;
            private set;
        }

    };

并将其作为参数传递给工作函数:

and passing this as an argument on the worker function:

// cts is an instance variable which can be triggered by another thread in parent appdomain
cts = new CancellationTokenSource();
InterAppDomainAbort abortFlag = new InterAppDomainAbort(cts.Token);
objectInRemoteAppDomain = childDomain.CreateInstanceAndUnwrap(...);

// this call will block for a long while the work is being performed.
objectInRemoteAppDomain.DoWork(abortFlag);

但是当 objectInRemoteAppDomain 尝试访问 Token getter 属性时,我仍然收到异常:

But I still get an exception when the objectInRemoteAppDomain tries to access the Token getter property:

System.Runtime.Serialization.SerializationException: Type 'System.Threading.CancellationToken' in Assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable.

我的问题是:如何在应用程序域中传播中止/取消信号并唤醒可能在 .NET 并发数据结构(支持 CancellationToken 参数)中阻塞的线程.

My question is: How can I propagate the abort/cancellation signal across the appdomains and wake up threads that may be blocked in .NET concurrency data structures (where CancellationToken arguments are supported).

推荐答案

我已经有一段时间没有看过任何跨 AppDomain 的东西了,所以这段代码可能存在我没有意识到的问题,但似乎做这份工作.根本问题是似乎没有办法将 CancellationToken[Source] 从一个 AppDomain 转移到另一个.所以我创建了两个来源,主要设置为在适当的时候取消辅助.

It's been a while since I looked at any cross-AppDomain stuff, so there might be problems with this code that I haven't realised, but it seems to do the job. The fundamental problem is that there seems no way to transfer a CancellationToken[Source] from one AppDomain to another. So I create two sources, with the primary set up to cancel the secondary when appropriate.

在这种情况下两个单独的令牌源的事实当然可能是一个问题,但我认为您没有解决缺乏可序列化阻止您使用的事实无论如何,在两个独立的 AppDomain 中使用相同的一个.

The fact that there are two separate token sources in this scenario could of course be a problem, but I don't think you're getting around the fact that lack of serialisability prevents you from using the same one in two separate AppDomains anyway.

关于最小错误检查、Dispose 实现等的标准警告

Standard caveats about minimal error-checking, Dispose implementations, etc.

// I split this into a separate interface simply to make the boundary between
// canceller and cancellee explicit, similar to CancellationTokenSource itself.
public interface ITokenSource
{
    CancellationToken Token { get; }
}

public class InterAppDomainCancellable: MarshalByRefObject,
                                        ITokenSource,
                                        IDisposable
{
    public InterAppDomainCancellable()
    {
        cts = new CancellationTokenSource();
    }

    public void Cancel() { cts.Cancel(); }

    // Explicitly implemented to make it less tempting to call Token
    // from the wrong side of the boundary.
    CancellationToken ITokenSource.Token { get { return cts.Token; } }

    public void Dispose() { cts.Dispose(); }

    private readonly CancellationTokenSource cts;
}

// ...

// Crucial difference here is that the remotable cancellation source
// also lives in the other domain.
interAppDomainCancellable = childDomain.CreateInstanceAndUnwrap(...);

var primaryCts = new CancellationTokenSource();
// Cancel the secondary when the primary is cancelled.
// CancellationToken.Register returns a disposable object which unregisters when disposed.
using (primaryCts.Token.Register(() => interAppDomainCancellable.Cancel()))
{
    objectInRemoteAppDomain = childDomain.CreateInstanceAndUnwrap(...);
    // DoWork expects an instance of ITokenSource.
    // It can access Token because they're all in the same domain together.
    objectInRemoteAppDomain.DoWork(interAppDomainCancellable);
    // ... some other work which might cancel the primary token.
}

这篇关于如何跨 AppDomain 边界传递 CancellationToken?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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