加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 如何通过AppDomain边界的CancellationToken通过?

发布时间:2020-12-15 06:53:05 所属栏目:百科 来源:网络整理
导读:我有一个命令对象,根据请求队列的请求进行工作.这个特定的命令将在一个子应用程序域中执行它的工作.在子应用程序中执行其工作的一部分涉及阻止ConcurrentQueue操作(例如,Add或Take).我需要能够通过请求队列传播中止信号,跨越到子应用程序域,并唤醒其中的工作
我有一个命令对象,根据请求队列的请求进行工作.这个特定的命令将在一个子应用程序域中执行它的工作.在子应用程序中执行其工作的一部分涉及阻止ConcurrentQueue操作(例如,Add或Take).我需要能够通过请求队列传播中止信号,跨越到子应用程序域,并唤醒其中的工作线程.

因此,我认为我需要通过AppDomain边界的CancellationToken.

我尝试创建一个继承自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;
        }

    };

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

// 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尝试访问令牌getter属性时,我仍然会收到异常:

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.

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

解决方法

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

事实上,在这种情况下有两个单独的令牌来源当然可能是一个问题,但是我不认为你不知道缺少可序列性阻止你在两个单独的AppDomains中使用相同的一个.

关于最小错误检查,Dispose实现等的标准注意事项

// 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.
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);

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读