1

我正在考虑创建一个 ServiceManager 区域(一组具有外观接口的类),其他区域可以通过该区域注册并提供“服务”,并传递请求。我计划在它自己的线程中运行这个类,并且我希望将关键区域保持在最低限度,并且完全在这个区域内处理。

当一个区域注册时,他们会获得自己的收件箱和发件箱,即服务请求列表。

现在我的困境是,如果我不共享发件箱(服务提供商区域)的链接,我将需要通过搜索匹配找到该框(所有注册的关键区域,因此所有提交请求为好吧,违背了本地发件箱的目的)。

替代方案我在 ServiceManager 区域之外提供一个链接,然后编码一个新的外部区域,可以跳过关键区域并直接更新列表,绕过这个。


我的解决方案是在 ServiceManager 区域的代码中创建一个“关键”对象,直接访问永远不会离开该区域(包括完全空的任何对象都可以使用)。

当一个区域被注册时,他们会得到一个类作为回报,其中一个指向上述对象的链接以及一个指向已注册区域的 ServiceManager 对象的链接。(其中包含直接收件箱/发件箱链接以及其他信息)。

此“令牌”对象还包含以下代码

public ServiceObject GetServiceObject(Key key)
{
    If (key == this.key)
    {
        return serviceObject;
    }
    return null
{

这样,即使命令是公开的,它的内容也只能在 ServiceManager 区域内访问,因为它是唯一可以直接访问 Key 对象的区域。这绕过了所有服务用户共享关键区域的两个问题,以及这些服务用户直接访问他们的列表的风险。

所以它解决了问题,但对我来说这看起来真的很难看,有没有更聪明的方法,如果怎么做?

4

2 回答 2

1

使用 System.Collections.Concurrent 中的类 - 它们具有高效的锁定实现,还提供生产者/消费者行为以及用于分配工作负载的分区。

使用这些类,您将能够对任何场景进行建模,无论您有许多读者、许多作者,还是同时拥有这两种情况。所有这些都无需编写您自己的任何锁定代码。

更新:包装队列的示例代码为将来可选的命令队列拆分为多个队列提供外观。

让我们假设您对将命令插入队列的线程数量的关注有一些好处。您可以通过在底层队列周围创建一个瘦包装器来保护自己,如果您将来发现这是必要的,它允许您传递不同的包装器实例。

public interface ICommandQueue {
     void Add( Command command );
}

public class CommandQueue : ICommandQueue {
     private ConcurrentQueue<Command> queue = new ConcurrentQueue<Command>();

     public void Add( Command command ) {
         queue.Enqueue( command );
     }
}

实例化 ServiceObject 时,请确保在构造函数中传入 ICommandQueue 实例(手动或使用 IoC 容器),或者使用静态 CommandQueueFactory 让 SO 按需获取它,如果这对您更有效。

public class ServiceObject {
     private ICommandQueue queue;

     public ServiceObject( ICommandQueue queue ) {
         this.queue = queue;
     }
}

这将允许您稍后更改队列数量,而不是现在编写所有(可能不必要的)代码。永远不要解决你不确定的问题:-)

更多信息:

于 2013-04-28T13:35:14.240 回答
0

我目前使用的代码是这样的。

//base class of no use on its own. Used to lock the AreaIdentifier
public class Key
{
    public Key()
    {
    }
}

//public direct link to ServiceArea info, without ability to access it without the internal key
public class AreaIdentifier
{
    Key key;
    ServiceArea serviceArea;
    public AreaIdentifier(ServiceArea serviceArea, Key key)
    {
        this.key = key;
        this.serviceArea = serviceArea;
    }

    public ServiceArea GetServiceArea(Key key)
    {
        if (this.key == key) return serviceArea;
        return null;
    }
}

}

采用这种方法的原因是外部区域必须以“传输层”的“内部代码”以及添加和删除不会弄乱动作的方式进行编码。现在如果我分享一个直接链接

因此,当外部区域(在它自己的线程中)想要添加一个新命令时,它通过调用位于通信层代码中的以下调用来实现。(该区域内有一个私有 Key 变量,不能通过 AreaIdentifier 访问(但已知),也不能以该区域外的其他方式共享。

    //Put a command in the outBox for pickup by CommunicationLayer
    public Boolean AddCommand(AreaIdentifier area, CommandRequest command)
    {
         //attempt enter critical region or return false;             
         ServiceArea temparea = area.GetServiceArea(key);
         List<Command> tempOutbox = temparea.GetOutBox();
         tempOutbox.Add(command);
         //exit critical region
         return true;
    }

我从这种方法中看到的唯一缺点是我有“GetServiceArea”的公共功能,这在 TransportLayer 的“内部”功能之外几乎没有意义

于 2013-04-29T14:15:27.043 回答