Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 确保在区域内访问对象(列表),但可在外部引用的策略_C#_Multithreading - Fatal编程技术网

C# 确保在区域内访问对象(列表),但可在外部引用的策略

C# 确保在区域内访问对象(列表),但可在外部引用的策略,c#,multithreading,C#,Multithreading,我正在考虑创建一个ServiceManager区域(一组带有门面接口的类),其他区域可以通过该区域注册并提供“服务”,并传递请求。我计划在它自己的线程中运行这个类,并且我希望将关键区域保持在最小值,并且完全在这个区域内处理 当一个区域注册时,他们会得到自己的收件箱和发件箱命令,这是一个ServiceRequests列表 现在,我的困境是,如果我不共享发件箱(服务提供商区域)的链接,我将需要通过搜索匹配项来定位发件箱(所有注册的关键区域,并且由于这一点,所有提交的请求也会破坏本地发件箱的目的) 备

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

当一个区域注册时,他们会得到自己的收件箱和发件箱命令,这是一个ServiceRequests列表

现在,我的困境是,如果我不共享发件箱(服务提供商区域)的链接,我将需要通过搜索匹配项来定位发件箱(所有注册的关键区域,并且由于这一点,所有提交的请求也会破坏本地发件箱的目的)

备选方案我在ServiceManager区域之外提供一个链接,然后对一个新的外部区域进行编码,这样就可以跳过关键区域,直接更新列表,绕过此区域


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

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

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

public ServiceObject GetServiceObject(Key key)
{
    If (key == this.key)
    {
        return serviceObject;
    }
    return null
{
这样,即使命令是公共的,其内容也只能在ServiceManager区域内访问,因为它是唯一可以直接访问密钥对象的区域。这绕过了上述两个问题:在所有服务用户之间共享关键区域,以及这些服务用户直接访问其列表的风险


因此,它解决了问题,但对我来说,这看起来真的很难看,有没有更聪明的方法,以及如何使用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 );
     }
}
这将允许您在以后更改队列的数量,而不是现在编写所有(可能不必要的)代码。永远不要解决一个你不确定的问题:-)

更多信息:


使用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 );
     }
}
这将允许您在以后更改队列的数量,而不是现在编写所有(可能不必要的)代码。永远不要解决一个你不确定的问题:-)

更多信息:


我目前使用的代码如下所示

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

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

因此,当外部区域(在它自己的线程中)想要添加一个新命令时,它通过调用位于通信层代码中的以下调用来完成。(此区域内有一个私钥变量,无法通过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;
    }
//将命令放入发件箱,以便通信层拾取
公共布尔AddCommand(AreaIdentifier区域,CommandRequest命令)
{
//试图进入关键区域或返回false;
ServiceArea temparea=area.GetServiceArea(键);
List tempOutbox=temparea.GetOutBox();
添加(命令);
//出口临界区
返回true;
}

我从这种方法中看到的唯一缺点是,我有“GetServiceArea”的公共功能,这在TransportLayer的“内部”功能之外没有什么意义。我目前使用的代码是这样的

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

采用这种方法的原因是,外部区域的编码方式必须确保“传输层”的“内部代码”以及添加和删除操作不会弄乱操作

因此,当外部区域(在它自己的线程中)想要添加一个新命令时,它会通过调用位于通信层代码中的以下调用来完成。(该区域内有一个私钥变量,不能通过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;
    }
//将命令放入发件箱,以便通信层拾取
公共布尔添加命令(A)