代码之家  ›  专栏  ›  技术社区  ›  ChaosPandion

当我向演员传递消息时,如何绕过我的“对象引用”问题?

  •  2
  • ChaosPandion  · 技术社区  · 15 年前

    不久前,我把一个简单的类 Actor 这是我对 Actor Model . 从那时起我就成功地使用了它( 减去一些恼人的解决方法,因为缺乏歧视性的工会类型。 )我只剩下一个问题,我不确定如何解决,而不会使课堂变得笨拙和缓慢。

    当某人定义一条消息时,他们当然有权包含对调用方自己可以操作的对象的引用。即使知道我将几乎是唯一一个使用这门课的人,这仍然困扰着我。

    一个很好的例子就是 Web Workers 在火狐中实现。当将对象传递给工作者时,它将被序列化为JSON。

    有什么想法吗?

    public abstract class Actor<T, U> : IDisposable
    {
        private const int AsyncChannelPoolSize = 20;
    
        private volatile bool _disposed;
        private readonly Thread _actorThread;
        private readonly AsyncReplyChannel<T, U> _messageChannel;
        private readonly Lazy<ObjectPool<AsyncChannel<U>>> _asyncChannelPool;
    
    
        public event EventHandler<ExceptionEventArgs> Exception;
    
    
        protected Actor()
        {
            _messageChannel = new AsyncReplyChannel<T, U>();
            _asyncChannelPool = new Lazy<ObjectPool<AsyncChannel<U>>>(() => new ObjectPool<AsyncChannel<U>>(AsyncChannelPoolSize));
            _actorThread = new Thread(ProcessMessages);
            _actorThread.IsBackground = true;
            _actorThread.Start();
        }
    
    
        public U PostWithReply(T value)
        {
            ThrowIfDisposed();
    
            var replyChannel = default(AsyncChannel<U>);
            var replyPackage = default(AsyncReplyPackage<T, U>);
            var replyMessage = default(U);
    
            try
            {
                replyChannel = _asyncChannelPool.Value.Get();
                replyPackage = new AsyncReplyPackage<T, U>(value, replyChannel);
                _messageChannel.Send(replyPackage);
                replyMessage = replyChannel.Receive();
            }
            finally
            {
                _asyncChannelPool.Value.Put(replyChannel);
            }
    
            return replyMessage;
        }
    
        public void PostWithAsyncReply(T value, IAsyncChannel<U> replyChannel)
        {
            ThrowIfDisposed();
            _messageChannel.Send(new AsyncReplyPackage<T, U>(value, replyChannel));
        }
    
        public void Dispose()
        {
            Dispose(true);
        }
    
        protected abstract void ProcessMessage(AsyncReplyPackage<T, U> package);
    
        protected virtual void OnException(Exception ex)
        {
            var exceptionEvent = Exception;
            if (exceptionEvent != null)
            {
                exceptionEvent(this, new ExceptionEventArgs(ex));
            }
        }
    
        protected virtual void Dispose(bool disposing)
        {
            _disposed = true;
            _messageChannel.Dispose();
            if (_asyncChannelPool.IsValueCreated)
            {
                _asyncChannelPool.Value.Dispose();
            }
        }
    
        private void ProcessMessages()
        {
            var package = default(AsyncReplyPackage<T, U>);
            while (_messageChannel.TryReceive(out package) && !_disposed)
            {
                try
                {
                    ProcessMessage(package);
                }
                catch (Exception ex)
                {
                    OnException(ex);
                }
            }
        }
    
        private void ThrowIfDisposed()
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }
        }
    }
    
    2 回复  |  直到 14 年前
        1
  •  1
  •   mqp    15 年前

    这不是一个好的解决方案,但你可以限制 T 成为 ICloneable 当你得到它的时候克隆它。这或多或少相当于您所描述的“序列化到JSON”方法的意识形态。不用说,这将是笨拙和缓慢的。

    实际上,您应该记住保持消息不变。C不是一种可以很好地为您实现这一点的语言。

        2
  •  0
  •   slugster Joey Cai    15 年前

    我认为你在这里没有问题-如果你的 _messageChannel 然后,被叫方将无法获取对原始对象的引用,他们将获取原始对象的副本。

    如果在调用完成后得到返回给您的“引用”很重要,那么您可能需要考虑使用标识符,而不是仅仅依赖于类引用,然后使用该标识符来定位原始对象。