環形緩衝區.ringbuff(C#和java)

環形緩衝,java

本質就是隊列fifo,先進先出的特殊版本,環形隊列,是用空間獲得了順序存儲的快索引的優勢,又避免了刪除,移動數據的缺點。而且還享受了單生產/單消費,2線程的無鎖線程優點。十分完美。c++

1.面對頻率超級頻繁的讀寫,環形緩衝修改成固定大小的隊列,不添加操做,而且使用後,也不刪除和移動。壞處是,必須預設內存空間。因此適合超級頻繁的讀寫,反正基本是一直佔用。c#

2.由於要實現環形,因此通常有2個哨兵,若是是2個線程,一個讀一個寫。環形緩衝,還能夠避免線程鎖。很是棒。即所謂單生產/單消費模式的共享隊列是不須要加鎖同步的數組

3.固定大小。因此數組 xxx[],很是適合改造爲環形緩衝。char[] 改成字符羣緩衝 . object[] 改成對象羣緩衝緩存

花了點時間,寫了下。測試用例測試了下。沒發現問題。服務器

感受緩存區必須根據實際狀況寫特例。多線程

這裏緩存區,適合 讀必須大於寫。app

特色dom

1.寫滿會 自動跳過。 因此須要根據狀況,定製緩存區大小,或者改寫爲自動擴大緩存區。性能

2.讀,若是無數據會直接出去,無阻塞.

3. 若是可行的話,可使用多個ringbuff,來代替多線程的方案

需改進:

定義一個最大緩存區大小。讓緩存區能夠自動擴大,到最大就不擴大了。

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BaseLib
{
    /// <summary>
    /// 環形緩衝區. c# byte== c++ unsign char . c# char==c ++ char.
    /// 環形緩衝結構,不考慮在讀或寫某端有多線程的狀況,由於環形緩衝結構就是爲了避免鎖下的性能,適合讀寫同一個線程,或者讀寫各一個線程。
    /// </summary>
    public class RingBuff
    {
        private byte[] ringBuff;
        private int nextWritePos;
        private int nextReadPos;
        private int buffSize;
        private int capcity;

        public RingBuff(int _size)
        {
            capcity=buffSize = _size;
            ringBuff = new byte[buffSize];
            nextWritePos = 0;
            nextReadPos = 0;
        }
  
        /// <summary>
        /// 寫入緩存
        /// </summary>
        /// <param name="_buff">要寫入的數據</param>
        /// <returns>是否寫入</returns>
        public bool WriteBuff(byte[] _buff)
        {
            bool ret = false;
            int bsize = _buff.Length;
            if (capcity < bsize)
            {
                ret = false;
            }
            else
            {
                int rightLeft = buffSize - nextWritePos;
                //need reture to head
                if (bsize > rightLeft)
                {
                    Array.Copy(_buff, 0, ringBuff, nextWritePos, rightLeft);
                    Array.Copy(_buff, rightLeft, ringBuff, 0, bsize - rightLeft);
                    nextWritePos = bsize - rightLeft;
                }
                else if (bsize == rightLeft)
                {
                    Array.Copy(_buff, 0, ringBuff, nextWritePos, bsize);
                    nextWritePos = 0;
                }
                else
                {
                    Array.Copy(_buff, 0, ringBuff, nextWritePos, bsize);
                    nextWritePos += bsize;
                }
                capcity = capcity - bsize;
                ret = true;
            }
            return ret;
        }
        /// <summary>
        /// 寫入緩存,指定讀取源的長度.
        /// </summary>
        /// <param name="_buff"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public bool WriteBuff(byte[] _buff, int len)
        {
            int bsize = len;// _buff.Length;
            bsize = len > _buff.Length ? _buff.Length : bsize;
            if (capcity < bsize)
            {
                return false;
            }
            else
            {
                int rightLeft = buffSize - nextWritePos;
                //need reture to head
                if (bsize > rightLeft)
                {
                    Array.Copy(_buff, 0, ringBuff, nextWritePos, rightLeft);
                    Array.Copy(_buff, rightLeft, ringBuff, 0, bsize - rightLeft);
                    nextWritePos = bsize - rightLeft;
                }
                else if (bsize == rightLeft)
                {
                    Array.Copy(_buff, 0, ringBuff, nextWritePos, bsize);
                    nextWritePos = 0;
                }
                else
                {
                    Array.Copy(_buff, 0, ringBuff, nextWritePos, bsize);
                    nextWritePos += bsize;
                }
                capcity -= bsize;
                return true;
            }
        }
        /// <summary>
        /// 讀緩存,是否預讀,而不移動讀哨兵.
        /// </summary>
        /// <param name="readbuff">讀入的臨時緩存</param>
        /// <returns>實際讀出的數據長度</returns>
        public int ReadBuff(ref byte[] readbuff, bool MovePosition = true)
        {
            int len = readbuff.Length;
            int enableread = buffSize - capcity;
            Array.Clear(readbuff, 0, len);
            if (len <= 0 || enableread <= 0)
            {
                return 0;
            }
            else
            {
                int realRead = enableread >= len ? len : enableread;
                int rightLeft = buffSize - nextReadPos;
                if (realRead > rightLeft)
                {
                    Array.Copy(ringBuff, nextReadPos, readbuff, 0, rightLeft);
                    Array.Copy(ringBuff, 0, readbuff, rightLeft, realRead - rightLeft);
                    if (MovePosition)
                    {
                        nextReadPos = realRead - rightLeft;
                    }
                }
                else if (realRead == rightLeft)
                {
                    Array.Copy(ringBuff, nextReadPos, readbuff, 0, realRead);
                    if (MovePosition)
                    {
                        nextReadPos = 0;
                    }
                }
                else
                {
                    Array.Copy(ringBuff, nextReadPos, readbuff, 0, realRead);
                    if (MovePosition)
                    {
                        nextReadPos += realRead;
                    }
                }
                capcity += realRead;
                return realRead;
            }
        }

        public string GetBuffInfo()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(System.Threading.Thread.CurrentThread.Name + ":writePositon:" + nextWritePos.ToString());
            sb.Append(".  readPosition:" + nextReadPos.ToString());
            sb.Append(".  size:");
            sb.Append(buffSize);
            sb.Append("   .enable read:" + (buffSize-capcity).ToString() + ".enable write:" + capcity.ToString());
            sb.Append(System.Environment.NewLine);

            sb.Append("1-10 byte: ");

            for (int i = 0; i < 10; i++)
            {
                sb.Append(ringBuff[i].ToString("x")+"|");
            }

            return sb.ToString();
        }
        private RingBuff()
        { }
    }
}

 

 

測試例子

 

 static void TestRingBuff()
        {
            int buffSize = 10;
            BaseLib.RingBuff rb = new BaseLib.RingBuff(buffSize);
            Console.WriteLine(rb.GetBuffInfo());

            ////測試讀滿,和寫滿。
            //for (int i = 0; i < 12; i++)
            //{
            //    rb.WriteBuff(new byte[] { (byte)testChar });
            //    testChar++;
            //    Console.WriteLine(rb.GetBuffInfo());
            //}

            //byte[] tempReadBuff = new byte[1];
            //for (int i = 0; i < 15; i++)
            //{
            //    rb.ReadBuff(ref tempReadBuff);
            //    Console.WriteLine(tempReadBuff[0].ToString("x"));
            //    Console.WriteLine(rb.GetBuffInfo());
            //}

            //////字符是依次 + 1寫入緩存。因此測試首先關注各類狀況下,是否讀出的數據是聯繫的。就可大概肯定數據是沒有丟失和跳躍的。
            ////測試讀慢,寫快.
            //while (true)
            //{
            //    bool ret = rb.WriteBuff(new byte[] { (byte)testChar, (byte)++testChar, (byte)++testChar });
            //    if (ret == false)
            //    {
            //        --testChar;
            //        --testChar;
            //        --testChar;
            //    }
            //    Console.WriteLine(rb.GetBuffInfo());
            //    byte[] tempReadBuff = new byte[2];
            //    rb.ReadBuff(ref tempReadBuff);
            //    Console.WriteLine(tempReadBuff[0].ToString("x") + "." + tempReadBuff[1].ToString("x"));
            //    ++testChar;
            //    System.Threading.Thread.Sleep(1000);
            //}

            ////測試讀快,慢寫
            //while (true)
            //{
            //    bool ret = rb.WriteBuff(new byte[] { (byte)testChar, (byte)++testChar });
            //    if (ret == false)
            //    {
            //        --testChar;
            //        --testChar;
            //    }
            //    Console.WriteLine(rb.GetBuffInfo());
            //    byte[] tempReadBuff = new byte[3];
            //    rb.ReadBuff(ref tempReadBuff);
            //    Console.WriteLine(tempReadBuff[0].ToString() + "." + tempReadBuff[1].ToString() + "." + tempReadBuff[2].ToString());
            //    Console.WriteLine(rb.GetBuffInfo());
            //    ++testChar;
            //    System.Threading.Thread.Sleep(1000);
            //}

            //////隨機測試。
            //while (true)
            //{
            //    bool ret = rb.WriteBuff(new byte[] { (byte)testChar, (byte)++testChar, (byte)++testChar });
            //    if (ret == false)
            //    {
            //        --testChar;
            //        --testChar;
            //        --testChar;
            //    }
            //    Console.WriteLine(rb.GetBuffInfo());

            //    Random rd = new Random();
            //    int rint = (rd.Next() + 2) % 10;

            //    byte[] tempReadBuff = new byte[rint];
            //    Console.Write("read " + rint.ToString("x") + " :");
            //    rb.ReadBuff(ref tempReadBuff);
            //    for (int i = 0; i < rint; ++i)
            //    {
            //        Console.Write(tempReadBuff[i].ToString("x") + " ");
            //    }
            //    Console.Write("\r\n");
            //    Console.WriteLine(rb.GetBuffInfo());
            //    ++testChar;
            //    System.Threading.Thread.Sleep(1000);
            //}

            Console.Read();
        }

 

 

java 版本

明顯發現java和c#基本語法就像雙胞胎。爲何好多人包括以前的本身,會排斥另外一種語言呢?

特定:讀完,寫滿,以後都不工做了。

unusedSize;//冗餘這個字段既能夠提升效率,也能夠區分空仍是滿的狀況(單靠2個指針區分不了)。
package com.datastructurn;

public class RingBuff
{
    private byte[] ringBuff;
    private Integer nextWritePosition;
    private Integer nextReadPosition;
    private Integer buffSize;
    private Integer unusedSize;//冗餘這個字段既能夠提升效率,也能夠區分空仍是滿的狀況(單靠2個指針區分不了)。
    
    
    public RingBuff(int _size)
    {
        buffSize= unusedSize=_size;
        ringBuff=new byte[buffSize];
        nextReadPosition=nextWritePosition=0;
    }
    
    
    public boolean WriteBuff(byte[] _buff)
    {
        boolean ret = false;
        int bsize = _buff.length;
        if (unusedSize < bsize)
        {
            ret = false;
        }
        else 
        {
            int rightLeft = buffSize - nextWritePosition;
            //need reture to head
            if (bsize > rightLeft)
            {
                
                System.arraycopy(_buff, 0, ringBuff, nextWritePosition, rightLeft);
                System.arraycopy(_buff, rightLeft, ringBuff, 0, bsize - rightLeft);
                nextWritePosition = bsize - rightLeft;
            }
            else if (bsize == rightLeft)
            {
                System.arraycopy(_buff, 0, ringBuff, nextWritePosition, bsize);
                nextWritePosition = 0;
            }
            else
            {
                System.arraycopy(_buff, 0, ringBuff, nextWritePosition, bsize);
                nextWritePosition += bsize;
            }
            unusedSize = unusedSize - bsize;
            
            
            ret = true;
        }
    
        return ret;
    }
    
    
     public boolean WriteBuff(byte[] _buff, int len)
     {
         int bsize = len;// _buff.Length;
         
         bsize = len > _buff.length ? _buff.length : bsize;
         if (unusedSize < bsize)
         {
             return false;
         }
         else
         {
             int rightLeft = buffSize - nextWritePosition;
             //need reture to head
             if (bsize > rightLeft)
             {
                 System.arraycopy(_buff, 0, ringBuff, nextWritePosition, rightLeft);
                 System.arraycopy(_buff, rightLeft, ringBuff, 0, bsize - rightLeft);
                 nextWritePosition = bsize - rightLeft;
             }
             else if (bsize == rightLeft)
             {
                 System.arraycopy(_buff, 0, ringBuff, nextWritePosition, bsize);
                 nextWritePosition = 0;
             }
             else
             {
                 System.arraycopy(_buff, 0, ringBuff, nextWritePosition, bsize);
                 nextWritePosition += bsize;
             }
             unusedSize -= bsize;
             return true;
         }
     }
     
     
      /// <summary>
     /// 讀緩存,是否預讀,而不移動讀哨兵.
     /// </summary>
     /// <param name="readbuff">讀入的臨時緩存</param>
     /// <returns>實際讀出的數據長度</returns>
     public int ReadBuff(byte[] readbuff, Boolean MovePosition )
     {
         if(MovePosition==null)
         {
             MovePosition=true;
         }
         
         int len = readbuff.length;
         int enableread = buffSize - unusedSize;
         //Array.Clear(readbuff, 0, len);
         if (len <= 0 || enableread <= 0)
         {
             return 0;
         }
         else
         {
             int realRead = enableread >= len ? len : enableread;
             int rightLeft = buffSize - nextReadPosition;
             if (realRead > rightLeft)
             {
                 System.arraycopy(ringBuff, nextReadPosition, readbuff, 0, rightLeft);
                 System.arraycopy(ringBuff, 0, readbuff, rightLeft, realRead - rightLeft);
                 if (MovePosition)
                 {
                     nextReadPosition = realRead - rightLeft;
                 }
             }
             else if (realRead == rightLeft)
             {
                 System.arraycopy(ringBuff, nextReadPosition, readbuff, 0, realRead);
                 if (MovePosition)
                 {
                     nextReadPosition = 0;
                 }
             }
             else
             {
                 System.arraycopy(ringBuff, nextReadPosition, readbuff, 0, realRead);
                 if (MovePosition)
                 {
                     nextReadPosition += realRead;
                 }
             }
             
             unusedSize += realRead;
             return realRead;
         }
     }
     
     public String GetBuffInfo()
     {
         StringBuilder sb = new StringBuilder();
         sb.append(":writePositon:" + nextWritePosition);
         sb.append(".  readPosition:" + nextReadPosition);
         sb.append(".  size:");
         sb.append(buffSize);
         sb.append("   .enable read:" + (buffSize-unusedSize) + ".enable write:" + unusedSize);
         sb.append("\r\n");

         sb.append("1-10 byte: ");

         for (int i = 0; i < 10; i++)
         {
             sb.append(ringBuff[i]);
         }

         return sb.toString();
     }
    
    
     
}

 

 

 

 

 

共享內存

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace control
{
    public class ShareMemory
    {
        [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
        public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
        //int+int+10*10=108int size = Marshal.SizeOf(typeof(char));
        public void CreateShareFile(int size)
        {
            using (var mmf = MemoryMappedFile.CreateFromFile(@"c:\aa.data", FileMode.Open, "test", size+12))
            {
                //經過指定的 偏移量和大小 建立內存映射文件視圖服務器
                using (var accessor = mmf.CreateViewAccessor()) //偏移量,能夠控制數據存儲的內存位置;大小,用來控制存儲所佔用的空間
                {
                    accessor.Write(0, 16);//nextWritePos
                    accessor.Write(4, 16);//nextReadPos;
                    accessor.Write(8, size);//buffSize
                    accessor.Write(12, size);//capcity
                }
            }
        }

        public int GetNextWritePos(MemoryMappedViewAccessor mmv)
        {
            return mmv.ReadInt32(0);
        }
        public void SetNextWritePos(MemoryMappedViewAccessor mmv,int value)
        {
            mmv.Write(0, value);
        }

        public int GetnextReadPos(MemoryMappedViewAccessor mmv)
        {
            return mmv.ReadInt32(4);
        }
        public void SetnextReadPos(MemoryMappedViewAccessor mmv, int value)
        {
            mmv.Write(4, value);
        }

        public int GetbuffSize(MemoryMappedViewAccessor mmv)
        {
            return mmv.ReadInt32(8);
        }

        public int Getcapcity(MemoryMappedViewAccessor mmv)
        {
            return mmv.ReadInt32(12);
        }
        public void Setcapcity(MemoryMappedViewAccessor mmv, int value)
        {
            mmv.Write(12, value);
        }


        public IntPtr changepd(byte[] write)  
        {  
            IntPtr write_data = Marshal.AllocHGlobal(write.Length);
                Marshal.Copy(write, 0, write_data, write.Length);  
            Marshal.FreeHGlobal(write_data );
            return write_data;
        }

    public bool Write(byte[] _buff)
        {
            bool ret = false;
            using (var mmf = MemoryMappedFile.CreateFromFile(@"c:\aa.data", FileMode.Open, "test", 108))
            {
                using (var accessor = mmf.CreateViewAccessor())
                {
                    int bsize = _buff.Length;
                    if (Getcapcity(accessor) < bsize)
                    {
                        ret = false;
                    }
                    else
                    {
                        int rightLeft = GetbuffSize(accessor) - GetnextReadPos(accessor);
                        if (bsize > rightLeft)
                        {
                            unsafe
                            {
                                byte* pb = (byte*)IntPtr.Zero;
                                accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref pb);
                                CopyMemory((IntPtr)(pb), changepd(_buff), (uint)_buff.Length);
                            }
                            
                            
                            //Array.Copy(_buff, 0, ringBuff, nextWritePos, rightLeft);
                            //Array.Copy(_buff, rightLeft, ringBuff, 0, bsize - rightLeft);
                            SetNextWritePos(accessor, bsize - rightLeft);
                        }
                        else if (bsize == rightLeft)
                        {
                            //Array.Copy(_buff, 0, ringBuff, nextWritePos, bsize);
                            SetNextWritePos(accessor, 16);
                        }
                        else
                        {
                            //Array.Copy(_buff, 0, ringBuff, nextWritePos, bsize);
                            SetNextWritePos(accessor,GetnextReadPos(accessor)+bsize);
                        }
                        Setcapcity(accessor, Getcapcity(accessor) - bsize);
                        ret = true;
                    }
                }
            }

            return ret;
        }
    }
}
相關文章
相關標籤/搜索