Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.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
使LinkedRingBuffer线程的C#实现安全_C#_Performance_Linked List_Thread Safety_Buffer - Fatal编程技术网

使LinkedRingBuffer线程的C#实现安全

使LinkedRingBuffer线程的C#实现安全,c#,performance,linked-list,thread-safety,buffer,C#,Performance,Linked List,Thread Safety,Buffer,我有三个问题: 你一般认为我解决给定问题的方法如何 您认为我可以进一步提高性能吗 最重要的一点是:如何使我的实现真正线程安全 首先,我所处的简化场景是: 我通过消息系统与不同的设备进行通信。我在很短的时间内收到和发送了成千上万的信息。我在一个多线程环境中,因此许多不同的任务都在发送和等待消息。对于消息接收,事件驱动的方法给我们带来了很多麻烦,使其线程安全。 我有一些接收任务,这些任务从外部获取消息,并且必须将这些消息传递给许多消费者任务 所以我想出了一个不同的方法: 为什么不拥有几千条消息的历史

我有三个问题:

  • 你一般认为我解决给定问题的方法如何
  • 您认为我可以进一步提高性能吗
  • 最重要的一点是:如何使我的实现真正线程安全
  • 首先,我所处的简化场景是: 我通过消息系统与不同的设备进行通信。我在很短的时间内收到和发送了成千上万的信息。我在一个多线程环境中,因此许多不同的任务都在发送和等待消息。对于消息接收,事件驱动的方法给我们带来了很多麻烦,使其线程安全。 我有一些接收任务,这些任务从外部获取消息,并且必须将这些消息传递给许多消费者任务

    所以我想出了一个不同的方法: 为什么不拥有几千条消息的历史记录,其中每一条新消息都排队,并且使用者任务可以从最新的项目向后搜索到最后处理的项目,以获取所有新到达的消息。当然,这必须是快速和线程安全的

    我提出了链接环缓冲区的想法,并实现了以下功能:

      public class LinkedRingBuffer<T>
      {
         private LinkedRingBufferNode<T> firstNode;
         private LinkedRingBufferNode<T> lastNode;
    
         public LinkedRingBuffer(int capacity)
         {
            Capacity = capacity;
            Count = 0;
         }
    
         /// <summary>
         /// Maximum count of items inside the buffer
         /// </summary>
         public int Capacity { get; }
    
         /// <summary>
         /// Actual count of items inside the buffer
         /// </summary>
         public int Count { get; private set; }
    
         /// <summary>
         /// Get value of the oldest buffer entry
         /// </summary>
         /// <returns></returns>
         public T GetFirst()
         {
            return firstNode.Item;
         }
    
         /// <summary>
         /// Get value of the newest buffer entry
         /// </summary>
         /// <returns></returns>
         public T GetLast()
         {
            return lastNode.Item;
         }
    
         /// <summary>
         /// Add item at the end of the buffer. 
         /// If capacity is reached the link to the oldest item is deleted.
         /// </summary>
         public void Add(T item)
         {
            /* create node and set to last one */
            var node = new LinkedRingBufferNode<T>(lastNode, item);
            lastNode = node;
            /* if it is the first node, the created is also the first */
            if (firstNode == null)
               firstNode = node;
            /* check for capacity reach */
            Count++;
            if(Count > Capacity)
            {/* deleted all links to the current first so that its eventually gc collected */
               Count = Capacity;
               firstNode = firstNode.NextNode;
               firstNode.PreviousNode = null;
            }
         }
    
         /// <summary>
         /// Iterate through the buffer from the oldest to the newest item
         /// </summary>
         public IEnumerable<T> LastToFirst()
         {
            var current = lastNode;
            while(current != null)
            {
               yield return current.Item;
               current = current.PreviousNode;
            }
         }
    
         /// <summary>
         /// Iterate through the buffer from the newest to the oldest item
         /// </summary>
         public IEnumerable<T> FirstToLast()
         {
            var current = firstNode;
            while (current != null)
            {
               yield return current.Item;
               current = current.NextNode;
            }
         }
    
         /// <summary>
         /// Iterate through the buffer from the oldest to given item. 
         /// If item doesn't exist it iterates until it reaches the newest
         /// </summary>
         public IEnumerable<T> LastToReference(T item)
         {
            var current = lastNode;
            while (current != null)
            {
               yield return current.Item;
               if (current.Item.Equals(item))
                  break;
               current = current.PreviousNode;
            }
         }
    
         /// <summary>
         /// Iterate through the buffer from the newest to given item. 
         /// If item doesn't exist it iterates until it reaches the oldest
         /// </summary>
         public IEnumerable<T> FirstToReference(T item)
         {
            var current = firstNode;
            while (current != null)
            {
               yield return current.Item;
               if (current.Item.Equals(item))
                  break;
               current = current.PreviousNode;
            }
         }
    
         /// <summary>
         /// Represents a linked node inside the buffer and holds the data
         /// </summary>
         private class LinkedRingBufferNode<A>
         {
            public LinkedRingBufferNode(LinkedRingBufferNode<A> previousNode, A item)
            {
               Item = item;
               NextNode = null;
               PreviousNode = previousNode;
               if(previousNode != null)
                  previousNode.NextNode = this;
            }
            internal A Item { get; }
            internal LinkedRingBufferNode<A> PreviousNode { get; set; }
            internal LinkedRingBufferNode<A> NextNode { get; private set; }
         }
      }
    
    公共类linkedingbuffer
    {
    私有linkedingbuffernode firstNode;
    私有linkedingbuffernode lastNode;
    公共链接DringBuffer(内部容量)
    {
    容量=容量;
    计数=0;
    }
    /// 
    ///缓冲区内项目的最大计数
    /// 
    公共整数容量{get;}
    /// 
    ///缓冲区内项目的实际计数
    /// 
    公共整数计数{get;私有集;}
    /// 
    ///获取最早的缓冲区项的值
    /// 
    /// 
    公共T GetFirst()
    {
    返回firstNode.Item;
    }
    /// 
    ///获取最新缓冲区项的值
    /// 
    /// 
    公共T GetLast()
    {
    返回lastNode.Item;
    }
    /// 
    ///在缓冲区的末尾添加项。
    ///如果达到容量,则删除指向最旧项目的链接。
    /// 
    公共作废新增(T项)
    {
    /*创建节点并设置为最后一个*/
    var node=新的LinkedRingBufferNode(lastNode,item);
    lastNode=节点;
    /*如果它是第一个节点,则创建的也是第一个节点*/
    if(firstNode==null)
    第一个节点=节点;
    /*检查容量范围*/
    计数++;
    如果(计数>容量)
    {/*删除了指向当前第一个的所有链接,以便最终收集其gc*/
    计数=容量;
    firstNode=firstNode.NextNode;
    firstNode.PreviousNode=null;
    }
    }
    /// 
    ///从最早的项到最新的项遍历缓冲区
    /// 
    公共IEnumerable LastToFirst()
    {
    var电流=最后一个节点;
    while(当前!=null)
    {
    收益率返回当前项目;
    current=current.PreviousNode;
    }
    }
    /// 
    ///从最新项到最旧项遍历缓冲区
    /// 
    公共IEnumerable FirstToLast()
    {
    var电流=第一个节点;
    while(当前!=null)
    {
    收益率返回当前项目;
    current=current.NextNode;
    }
    }
    /// 
    ///从最早的项到给定项遍历缓冲区。
    ///如果项目不存在,它将迭代,直到到达最新的项目
    /// 
    公共IEnumerable LastToReference(T项)
    {
    var电流=最后一个节点;
    while(当前!=null)
    {
    收益率返回当前项目;
    if(当前项目等于(项目))
    打破
    current=current.PreviousNode;
    }
    }
    /// 
    ///从最新项到给定项迭代缓冲区。
    ///如果项不存在,它将迭代,直到它到达最早的项
    /// 
    公共IEnumerable FirstToReference(T项)
    {
    var电流=第一个节点;
    while(当前!=null)
    {
    收益率返回当前项目;
    if(当前项目等于(项目))
    打破
    current=current.PreviousNode;
    }
    }
    /// 
    ///表示缓冲区内的链接节点并保存数据
    /// 
    私有类LinkedRingBufferNode
    {
    公共LinkedRingBufferNode(LinkedRingBufferNode previousNode,一个项目)
    {
    项目=项目;
    NextNode=null;
    PreviousNode=PreviousNode;
    if(previousNode!=null)
    previousNode.NextNode=此;
    }
    内部项目{get;}
    内部LinkedIn BufferNode PreviousNode{get;set;}
    内部LinkedRingBufferNode下一个节点{get;private set;}
    }
    }
    
    但不幸的是,我对多线程环境有点陌生,那么如何使这个缓冲区线程对多次读写是安全的呢


    谢谢

    我认为最简单的方法是有一个同步
    对象
    ,每当执行线程关键代码时,您都会打开它。块中的代码称为,一次只能由一个线程访问。任何其他希望访问它的线程都将等待,直到释放锁

    定义和初始化:

    private object Synchro;
    
    public LinkedRingBuffer(int capacity)
    {
        Synchro = new object();
        // Other constructor code
    }
    
    public T GetFirst()
    {
        lock(Synchro)
        {
            return firstNode.Item;
        }
    }
    
    用法:

    private object Synchro;
    
    public LinkedRingBuffer(int capacity)
    {
        Synchro = new object();
        // Other constructor code
    }
    
    public T GetFirst()
    {
        lock(Synchro)
        {
            return firstNode.Item;
        }
    }
    
    在编写线程安全代码时,
    锁定
    某些部分似乎是显而易见的。但是,如果您不确定是否要锁定语句或代码块,为了读写安全,您需要考虑:

    • 此代码是否会影响任何其他锁定关键部分的行为或结果
    • 任何其他锁定的关键部分是否会影响此代码的行为或结果
    您还需要重写一些自动实现的属性,以便有一个备份字段。它是