美文网首页
C# 并发读写内存文件映射

C# 并发读写内存文件映射

作者: 流量地球 | 来源:发表于2019-08-16 13:09 被阅读0次

    using System;

    using System.Collections.Generic;

    using System.Runtime.InteropServices;

    using System.IO;

    using System.Linq;

    using System.Text;

    using System.Threading;

    using SharpGLWinformsApplication1.General;

    using System.Windows.Forms;

    using System.Collections;

    namespace SharpGLWinformsApplication1.General

    {

        #region 内存映射大文件

        public class ShareMemory

        {

            /*

            *0.获取文件句柄 :_lopen

            *1.创建内核文件获得句柄 : CreateFile

            *2.根据文件句柄获取共享内存句柄 :CreateFileMapping

            *3.根据读取共享内存大小获取数据块的句柄 : MapViewOfFile

            *4.根据数据块句柄读取文件内容到byte数组中

            *5.读完之后,清除使用过的句柄 : UnmapViewOfFile

            *6.获取下一块数据块大小和句柄,获取下一块内存大小

            *概述:首先要通过CreateFile()函数来创建或打开一个文件内核对象,这个对象标识了磁盘上将要用作内存映射文件的文件。在用CreateFile()将文件映像在物理存储器的位置通告给操作系统后,只指定了映像文件的路径,映像的长度还没有指定。为了指定文件映射对象需要多大的物理存储空间还需要通过CreateFileMapping()函数来创建一个文件映射内核对象以告诉系统文件的尺寸以及访问文件的方式。在创建了文件映射对象后,还必须为文件数据保留一个地址空间区域,并把文件数据作为映射到该区域的物理存储器进行提交。由MapViewOfFile()函数负责通过系统的管理而将文件映射对象的全部或部分映射到进程地址空间。此时,对内存映射文件的使用和处理同通常加载到内存中的文件数据的处理方式基本一样,在完成了对内存映射文件的使用时,还要通过一系列的操作完成对其的清除和使用过资源的释放。这部分相对比较简单,可以通过UnmapViewOfFile()完成从进程的地址空间撤消文件数据的映像、通过CloseHandle()关闭前面创建的文件映射对象和文件对象。

            */

            /// <summary>

            /// 获取当前线程文件句柄

            /// </summary>

            /// <param name="lpPathName">file path</param>

            /// <param name="iReadWrite"></param>

            /// <returns></returns>

            [DllImport("kernel32.dll")]

            public static extern IntPtr _lopen(string lpPathName, int iReadWrite);

            [DllImport("user32.dll", CharSet = CharSet.Auto)]

            public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);

            /// <summary>

            /// 创建共分享文件

            /// </summary>

            /// <param name="hFile">内核文件句柄</param>

            /// <param name="lpAttributes">安全模式</param>

            /// <param name="flProtect">打开模式,份配对句柄的权限,例如读写</param>

            /// <param name="dwMaxSizeHi">将文件大小转换成64进制的前32位高位</param>

            /// <param name="dwMaxSizeLow">将文件大小转换成64进制的后32位低位</param>

            /// <param name="lpName">文件名,不在一台机器上冲突就行</param>

            /// <returns></returns>

            [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]

            public static extern IntPtr CreateFileMapping(IntPtr hFile, IntPtr lpAttributes, uint flProtect, uint dwMaxSizeHi, uint dwMaxSizeLow, string lpName);

            [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]

            public static extern IntPtr OpenFileMapping(int dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, string lpName);

            /// <summary>

            /// 创建映射文件

            /// </summary>

            /// <param name="hFileMapping">创建映射文件句柄</param>

            /// <param name="dwDesiredAccess">安全模式</param>

            /// <param name="dwMaxSizeHi">将文件读到大小转换成64进制的前32位高位</param>

            /// <param name="dwMaxSizeLow">将文件读到大小转换成64进制的后32位低位</param>

            /// <param name="dwNumberOfBytesToMap">创建映射的大小,不设置也可以使用但是会抛异常,太大也会排异,建议50-10M</param>

            /// <returns></returns>

            [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]

            public static extern IntPtr MapViewOfFile(IntPtr hFileMapping, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);

            /// <summary>

            /// 关闭映射文件句柄资源占用

            /// </summary>

            /// <param name="handle">映射文件句柄</param>

            /// <returns></returns>

            [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]

            public static extern bool UnmapViewOfFile(IntPtr pvBaseAddress);

            /// <summary>

            /// 关闭文件句柄

            /// </summary>

            /// <param name="handle">文件句柄</param>

            /// <returns></returns>

            [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]

            public static extern bool CloseHandle(IntPtr handle);

            /// <summary>

            /// 获取上一个错误

            /// </summary>

            [DllImport("kernel32", EntryPoint = "GetLastError")]

            public static extern int GetLastError();

            [DllImport("kernel32.dll")]

            static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo);

            [StructLayout(LayoutKind.Sequential)]

            public struct SYSTEM_INFO

            {

                public ushort processorArchitecture;

                ushort reserved;

                public uint pageSize;

                public IntPtr minimumApplicationAddress;

                public IntPtr maximumApplicationAddress;

                public IntPtr activeProcessorMask;

                public uint numberOfProcessors;

                public uint processorType;

                public uint allocationGranularity;

                public ushort processorLevel;

                public ushort processorRevision;

            }

            /// <summary>

            /// 获取系统的分配粒度

            /// </summary>

            /// <returns></returns>

            public static uint GetPartitionsize()

            {

                SYSTEM_INFO sysInfo;

                GetSystemInfo(out sysInfo);

                return sysInfo.allocationGranularity;

            }

            const int ERROR_ALREADY_EXISTS = 183;

            const int FILE_MAP_COPY = 0x0001;

            const int FILE_MAP_WRITE = 0x0002;

            const int FILE_MAP_READ = 0x0004;

            const int FILE_MAP_ALL_ACCESS = 0x0002 | 0x0004;

            const int PAGE_READONLY = 0x02;

            const int PAGE_READWRITE = 0x04;

            const int PAGE_WRITECOPY = 0x08;

            const int PAGE_EXECUTE = 0x10;

            const int PAGE_EXECUTE_READ = 0x20;

            const int PAGE_EXECUTE_READWRITE = 0x40;

            const int SEC_COMMIT = 0x8000000;

            const int SEC_IMAGE = 0x1000000;

            const int SEC_NOCACHE = 0x10000000;

            const int SEC_RESERVE = 0x4000000;

            //文件句柄

            IntPtr m_fHandle;

            //共享内存文件句柄

            IntPtr m_hSharedMemoryFile = IntPtr.Zero;

            //当前句柄

            IntPtr m_pwData = IntPtr.Zero;

            //异步操作时下一个句柄

            IntPtr syn_m_pwData = IntPtr.Zero;

            bool m_bAlreadyExist = false;

            bool m_bInit = false;

            //缓冲区大小,初始化的值不一定被采用

            uint m_MemSize = 0x1400000;//20M

            //下一个数据块的长度

            public  uint nextMLength = 0;

            //读到的位置

            long m_offsetBegin = 0;

            //文件大小

            long m_FileSize = 0;

            public static IntPtr hTemplateFile = IntPtr.Zero;

            FileReader File = new FileReader();

            List<IntPtr> syn_m_pwDatas = new List<IntPtr>();

            public long get_m_FileSize()

            {

                return m_FileSize;

            }

            public long get_m_offsetBegin()

            {

                return m_offsetBegin;

            }

            //配合异步操作及时执行,

            public void do_syn_m_pwData()

            {

              m_pwData = syn_m_pwData;

            }

            public IntPtr get_m_pwData()

            {

                return m_pwData;

            }

            /// <summary>

            ///  初始化文件

            /// 解释:

            /// 1,可以指定读取块的大小,一般不使用

            /// </summary>

            /// <param name="MemSize">缓冲大小</param>

            /// <param name="filename">文件路径</param>

            public ShareMemory(string filename, uint memSize)

            {

                // 分页映射文件时,每页的起始位置startpos,必须为64K的整数倍。

                // memSize即缓存区的大小必须是系统分配粒度的整倍说,window系统的分配粒度是64KB

                this.m_MemSize = memSize;

                Init(filename);

            }

            /// <summary>.

            /// 初始化,常用的函数,执行的第1步

            /// 解释:

            /// 1,默认映射 GetPartitionsize()*800时52.4M缓冲//2000=131M

            /// 2,创建文件句柄,设置为读写模式,这是获取的第1个句柄,其他继承这个句柄都需要模式与上级模式相同

            /// </summary>

            /// <param name="filename"></param>

            public ShareMemory(string filename)

            {

                this.m_MemSize =  GetPartitionsize()*800;//2000=131M

                if (!System.IO.File.Exists(filename)) throw new Exception("未找到文件");

              // this.m_offsetBegin = this.m_MemSize;

                hTemplateFile = _lopen(filename, FILE_MAP_READ |FILE_MAP_WRITE );

                Init(filename);

            }

            //析构函数

            ~ShareMemory()

            {

              /// Close();

            }

            /// <summary>

            /// 初始化共享内存,第2步

            /// 解释:

            /// 1, File.Open(strName);,获取内核文件句柄,并获取读写访问权,第2个句柄

            /// 2,CreateFileMapping,获取共享文件句柄,并获取读写访问权,第3个句柄

            /// 共享内存名称

            /// 共享内存大小

            /// </summary>

            /// <param name="strName"></param>

            protected void Init(string strName)

            {

                //if (lngSize <= 0 || lngSize > 0x00800000) lngSize = 0x00800000;

                //创建文件IO

                System.IO.FileInfo f = new System.IO.FileInfo(strName);

                //获取文件大小

                m_FileSize = f.Length;

                //获取内核文件句柄

                m_fHandle = File.Open(strName);

                if (strName.Length > 0)

                {

                    //创建文件映射

                    //m_hSharedMemoryFile = CreateFileMapping(m_fHandle, IntPtr.Zero, (uint)PAGE_READONLY, 0, (uint)m_FileSize, "mdata");

                    //const int PAGE_READONLY = 0x02;

                    //const int PAGE_READWRITE = 0x04;

                    //const int PAGE_WRITECOPY = 0x08;

                    //const int PAGE_EXECUTE = 0x10;

                    //const int PAGE_EXECUTE_READ = 0x20;

                    //const int PAGE_EXECUTE_READWRITE = 0x40;

                    m_hSharedMemoryFile = CreateFileMapping(m_fHandle, IntPtr.Zero, (uint)PAGE_READWRITE, 0, (uint)m_FileSize/*(uint)m_FileSize-*/, "~MappingTemp");

                    if (m_hSharedMemoryFile == IntPtr.Zero)

                    {

                        m_bAlreadyExist = false;

                        m_bInit = false;

                        throw new Exception("CreateFileMapping失败LastError=" + GetLastError().ToString());

                    }

                    else

                        m_bInit = true;

                    ////映射第一块文件

                    //m_pwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_READ, 0, 0, (uint)m_MemSize);

                    //if (m_pwData == IntPtr.Zero)

                    //{

                    //    m_bInit = false;

                    //    throw new Exception("m_hSharedMemoryFile失败LastError=" + GetLastError().ToString());

                    //}

                }

            }

            /// <summary>

            /// 获取高32位

            /// </summary>

            /// <param name="intValue"></param>

            /// <returns></returns>

            private static uint GetHighWord(UInt64 intValue)

            {

                return Convert.ToUInt32(intValue >> 32);

            }

            /// <summary>

            /// 获取低32位

            /// </summary>

            /// <param name="intValue"></param>

            /// <returns></returns>

            private static uint GetLowWord(UInt64 intValue)

            {

                return Convert.ToUInt32(intValue & 0x00000000FFFFFFFF);

            }

            /// <summary>

            /// 获取下一个文件块 块大小为20M

            /// </summary>

            /// <returns>false 表示已经是最后一块文件</returns>

            public uint GetNextblock()

            {

                if (m_pwData != IntPtr.Zero && m_pwData != new IntPtr(-1))

                {

                    //卸载前一个文件

                    try { UnmapViewOfFile(m_pwData); }

                    catch { throw new Exception("缓存句柄销毁异常"); }

                }

                if (!this.m_bInit) throw new Exception("文件未初始化,at  GetNextblock。");

                //if ( m_offsetBegin + m_MemSize >= m_FileSize ) return false;

                uint m_Size = GetMemberSize();

                if (m_Size == 0) return m_Size;

                // 更改缓冲区大小

                m_MemSize = m_Size;

                //卸载前一个文件

                //bool l_result = UnmapViewOfFile( m_pwData );

                //m_pwData = IntPtr.Zero;

                //try

                //{

                    m_pwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_READ | FILE_MAP_WRITE, GetHighWord((UInt64)m_offsetBegin), GetLowWord((UInt64)m_offsetBegin), m_MemSize);

                    if (m_pwData == IntPtr.Zero)

                    {

                    //  MapViewOfFile(

                    //m_hSharedMemoryFile, // Handle to File Mapping object from CreateFileMapping()

                    //FILE_MAP_READ | FILE_MAP_WRITE, // FILE_MAP_ALL_ACCESS

                    //GetHighWord((UInt64)m_offsetBegin), // High order offset (32 bytes) in to start View.

                    //GetLowWord((UInt64)m_offsetBegin),

                    //0);

                        m_bInit = false;

                        if (GetLastError() == 8)

                            throw new Exception("映射文件块失败" + GetLastError().ToString() + ":存储空间不足,无法处理此命令");

                        throw new Exception("映射文件块失败" + GetLastError().ToString()+",at GetNextblock");

                    }

                //}

                //catch (Exception)

                //{

                //    MessageBox.Show("文件映射创建失败", "提示");

                //    try { this.Close(); }

                //    catch { }

                //}

                m_offsetBegin = m_offsetBegin + m_Size;

                return m_Size; //创建成功

            }

            /// <summary>

            /// 获取下一块数据句长和下个映射句柄,异步保存

            /// </summary>

            /// <returns></returns>

            public uint synGetNextblock()

            {

                if (!this.m_bInit) throw new Exception("文件未初始化,at  synGetNextblock。");

                //if ( m_offsetBegin + m_MemSize >= m_FileSize ) return false;

                uint m_Size = GetMemberSize();

                if (m_Size == 0)

                {

                    return m_Size;

                }

                // 更改缓冲区大小

                m_MemSize = m_Size;

                //卸载前一个文件

                //bool l_result = UnmapViewOfFile( m_pwData );

                //m_pwData = IntPtr.Zero;

                //try

                //{

                syn_m_pwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_READ | FILE_MAP_WRITE, GetHighWord((UInt64)m_offsetBegin), GetLowWord((UInt64)m_offsetBegin), m_MemSize);

                if (syn_m_pwData == IntPtr.Zero)

                {

                    //  MapViewOfFile(

                    //m_hSharedMemoryFile, // Handle to File Mapping object from CreateFileMapping()

                    //FILE_MAP_READ | FILE_MAP_WRITE, // FILE_MAP_ALL_ACCESS

                    //GetHighWord((UInt64)m_offsetBegin), // High order offset (32 bytes) in to start View.

                    //GetLowWord((UInt64)m_offsetBegin),

                    //0);

                    m_bInit = false;

                    if (GetLastError() == 8)

                        throw new Exception("映射文件块失败" + GetLastError().ToString() + ":存储空间不足,无法处理此命令");

                    throw new Exception("映射文件块失败" + GetLastError().ToString()+",at synGetNextblock");

                }

                //}

                //catch (Exception)

                //{

                //    MessageBox.Show("文件映射创建失败", "提示");

                //    try { this.Close(); }

                //    catch { }

                //}

                m_offsetBegin = m_offsetBegin + m_Size;

                return m_Size; //创建成功

            }

            /// <summary>

            /// 获取下一块数据的句柄

            /// </summary>

            /// <returns></returns>

            public IntPtr getNextblockIntPtr()

            {

                if (!this.m_bInit) throw new Exception("文件未初始化。");

                //if ( m_offsetBegin + m_MemSize >= m_FileSize ) return false;

                uint m_Size = GetMemberSize();

                if (m_Size == 0)

                {

                    return IntPtr.Zero;

                }

                // 更改缓冲区大小

                m_MemSize = m_Size;

                //卸载前一个文件

                //bool l_result = UnmapViewOfFile( m_pwData );

                //m_pwData = IntPtr.Zero;

                //try

                //{

                m_pwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_READ | FILE_MAP_WRITE, GetHighWord((UInt64)m_offsetBegin), GetLowWord((UInt64)m_offsetBegin), m_MemSize);

                if (m_pwData == IntPtr.Zero)

                {

                    m_bInit = false;

                    if (GetLastError() == 8)

                        throw new Exception("映射文件块失败" + GetLastError().ToString() + ":存储空间不足,无法处理此命令");

                    throw new Exception("映射文件块失败" + GetLastError().ToString());

                }

                //}

                //catch (Exception)

                //{

                //    MessageBox.Show("文件映射创建失败", "提示");

                //    try { this.Close(); }

                //    catch { }

                //}

                m_offsetBegin = m_offsetBegin + m_Size;

                return m_pwData; //创建成功

            }

            /// <summary>

            /// 返回映射区大小

            /// </summary>

            /// <returns></returns>

            private uint GetMemberSize()

            {

                if (m_offsetBegin >= m_FileSize)

                {

                    return 0;

                }

                else if (m_offsetBegin + m_MemSize >= m_FileSize)

                {

                    long temp = m_FileSize - m_offsetBegin;

                    return (uint)temp;

                }

                else

                    return m_MemSize;

            }

            /// <summary>

            /// 关闭内存映射

            /// </summary>

            public void Close()

            {

                if (m_bInit)

                {

                    UnmapViewOfFile(syn_m_pwData);

                    //syn_m_pwData = IntPtr.Zero;

                    //foreach遍历

                    foreach (IntPtr obj in syn_m_pwDatas)

                    {

                        UnmapViewOfFile(obj);

                    }

                    //UnmapViewOfFile(m_pwData);

                    //m_pwData = IntPtr.Zero;

                    ////try

                    ////{

                    CloseHandle(m_hSharedMemoryFile);

                    m_hSharedMemoryFile=IntPtr.Zero;

                    //}m_pwData

                    //catch (Exception)

                    //{

                    //    throw new Exception("在CloseHandle时" + "CreateFileMapping失败LastError=" + GetLastError().ToString());

                    //}

                    File.Close();

                    //try

                    //{

                    CloseHandle(hTemplateFile);

                    m_hSharedMemoryFile= IntPtr.Zero;

                    //}

                    //catch (Exception)

                    //{

                    //    throw new Exception("在CloseHandle时" + "CreateFileMapping失败LastError=" + GetLastError().ToString());

                    //}

                }

            }

            /// <summary>

            /// 从当前块中获取数据

            /// </summary>

            /// <param name="bytData">数据</param>

            /// <param name="lngAddr">起始数据</param>

            /// <param name="lngSize">数据长度,最大值=缓冲长度</param>

            /// <param name="Unmap">读取完成是否卸载缓冲区</param>

            /// <returns></returns>

            public void Read(ref byte[] bytData, int lngAddr, int lngSize, bool Unmap)

            {

                if (lngAddr + lngSize > m_MemSize)

                    throw new Exception("Read操作超出数据区");

                if (m_bInit)

                {

                    // string bb = Marshal.PtrToStringAuto(m_pwData);//

                    Marshal.Copy(m_pwData, bytData, lngAddr, lngSize);

                }

                else

                {

                    throw new Exception("文件未初始化");

                }

                if (Unmap)

                {

                    bool l_result = UnmapViewOfFile(m_pwData);

                    if (l_result)

                    m_pwData = IntPtr.Zero;

                }

            }

            /// <summary>

            /// 从当前块中获取数据

            /// </summary>

            /// <param name="bytData">数据</param>

            /// <param name="lngAddr">起始数据</param>

            /// <param name="lngSize">数据长度,最大值=缓冲长度</param>

            /// <exception cref="Exception: Read操作超出数据区"></exception>

            /// <exception cref="Exception: 文件未初始化"></exception>

            /// <returns></returns>

            public void Read(ref byte[] bytData, int lngAddr, int lngSize)

            {

                //if (lngAddr + lngSize > m_MemSize)

                //    throw new Exception("Read操作超出数据区");

                if (m_bInit)

                {

                    try

                    {

                        //m_pwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_COPY | FILE_MAP_READ | FILE_MAP_WRITE, GetHighWord((UInt64)m_offsetBegin), GetLowWord((UInt64)m_offsetBegin), IntPtr.Zero);

                        if (m_pwData == IntPtr.Zero || m_pwData ==new IntPtr(-1)) throw new Exception("读取时获得句柄异常");

                        Marshal.Copy(m_pwData, bytData, lngAddr, lngSize);

                    }

                    catch (Exception)

                    {

                        throw new Exception("在Read时读取長度超限度" + "CreateFileMapping失败LastError=" + GetLastError().ToString());

                    }

                }

                else

                {

                    throw new Exception("文件未初始化");

                }

            }

            /// <summary>

            /// 异步读文件

            /// </summary>

            /// <param name="bytData"></param>

            /// <param name="lngAddr"></param>

            /// <param name="lngSize"></param>

            public void synRead(ref byte[] bytData, int lngAddr, int lngSize)

            {

                //if (lngAddr + lngSize > m_MemSize)

                //    throw new Exception("Read操作超出数据区");

                if (m_bInit)

                {

                    try

                    {

                        //m_pwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_COPY | FILE_MAP_READ | FILE_MAP_WRITE, GetHighWord((UInt64)m_offsetBegin), GetLowWord((UInt64)m_offsetBegin), IntPtr.Zero);

                        if (m_pwData == IntPtr.Zero || m_pwData == new IntPtr(-1)) throw new Exception("读取时获得句柄异常");

                        Marshal.Copy(m_pwData, bytData, lngAddr, lngSize);

                        UnmapViewOfFile(m_pwData);

                        //syn_m_pwDatas.Add(m_pwData);

                        //if (syn_m_pwDatas.Count >=6)

                        //{

                        //    UnmapViewOfFile(syn_m_pwDatas[0]);

                        //    syn_m_pwDatas.RemoveAt(0);

                        //}

                    }

                    catch (Exception)

                    {

                        throw new Exception("在Read时读取長度超限度" + "CreateFileMapping失败LastError=" + GetLastError().ToString());

                    }

                }

                else

                {

                    throw new Exception("文件未初始化,at  synRead");

                }

            }

            /// <summary>

            /// 从当前块中获取数据

            /// </summary>

            /// <param name="lngAddr">缓存区偏移量</param>

            /// <param name="byteData">数据数组</param>

            /// <param name="StartIndex">数据数组开始复制的下标</param>

            /// <param name="lngSize">数据长度,最大值=缓冲长度</param>

            /// <exception cref="Exception: 起始数据超过缓冲区长度"></exception>

            /// <exception cref="Exception: 文件未初始化"></exception>

            /// <returns>返回实际读取值</returns>

            public uint ReadBytes(int lngAddr, ref byte[] byteData, int StartIndex, uint intSize)

            {

                if (lngAddr >= m_MemSize)

                    throw new Exception("起始数据超过缓冲区长度");

                if (lngAddr + intSize > m_MemSize)

                    intSize = m_MemSize - (uint)lngAddr;

                if (m_bInit)

                {

                    IntPtr s = new IntPtr((long)m_pwData + lngAddr); // 地址偏移

                    Marshal.Copy(s, byteData, StartIndex, (int)intSize);

                }

                else

                {

                    throw new Exception("文件未初始化");

                }

                return intSize;

            }

            /// <summary>

            /// 写数据

            /// </summary>

            /// <param name="bytData">数据</param>

            /// <param name="lngAddr">起始地址</param>

            /// <param name="lngSize">个数</param>

            /// <returns></returns>

            private int Write(byte[] bytData, int lngAddr, int lngSize)

            {

                if (lngAddr + lngSize > m_MemSize) return 2; //超出数据区

                if (m_bInit)

                {

                    Marshal.Copy(bytData, lngAddr, m_pwData, lngSize);

                }

                else

                {

                    return 1; //共享内存未初始化

                }

                return 0; //写成功

            }

        }

        internal class FileReader

        {

            const int GENERIC_READ = -2147483648;//0x80000000;

            public const int GENERIC_WRITE = 0x40000000;

            const uint OPEN_EXISTING = 3;

            public const int FILE_ATTRIBUTE_NORMAL = 0x80;

            ////0x80000000;读2G

            public const int FILE_FLAG_SEQUENTIAL_SCAN = 0x8000000;

            System.IntPtr handle;

            [DllImport("kernel32", SetLastError = true)]

            public static extern System.IntPtr CreateFile(

                string FileName,          // file name

                int DesiredAccess,      // access mode

                FileShare ShareMode,          // share mode

                IntPtr SecurityAttributes,  // Security Attributes

                FileMode CreationDisposition, // how to create

                int FlagsAndAttributes,  // file attributes

                IntPtr hTemplateFile        // handle to template file

            );

            [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]

            //关闭文件句柄

            static extern bool CloseHandle

            (

                System.IntPtr hObject // handle to object

            );

            //创建文件句柄

            public IntPtr Open(string FileName)

            {

                // open the existing file for reading     

                handle = CreateFile

                (

                    FileName,

                    GENERIC_READ | GENERIC_WRITE,

                    FileShare.Read | FileShare.Write,

                    IntPtr.Zero,

                    FileMode.Open,

                    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,

                    ShareMemory.hTemplateFile

                );

                if ( handle != System.IntPtr.Zero )

                {

                    return handle;

                }

                else

                {

                    throw new Exception( "打开文件失败" );

                }

            }

            //private IntPtr CreateFile(string FileName, uint GENERIC_READ, int p1, int p2, uint OPEN_EXISTING, int p3, IntPtr intPtr)

            //{

            //    throw new NotImplementedException();

            //}

            public bool Close()

            {

                bool temp =CloseHandle(handle);

                handle = IntPtr.Zero;

                return temp;

            }

        }

        #endregion

    }

    //并发部分

    #region syn_pcap 异步内存映射读取

            /// <summary>

            /// 异步多核三个线程读取paca文件信息的入口函数,主要功能是计算byte数组

            /// 解释:

            /// 1,执行parsePcapSyn,初始化数据,获取第一块映射的全部数据数据以执行parsePcapSyn第一次循环到达等待第二层getBytesSyn执行完毕返回数据数据,获取第二包映射数组长度和句柄,以执行第一次getBytesSyn的执行,直到等待第三层getIntPtrSyn执行完毕返回数据数据。

            /// 2,进入 while (leftLength > 0)循环,while (!ar.IsCompleted) 确保执行到此处还有数据没有读完,还有循环读取一个数据块的内容

            /// 3,while (temp < 0)这里判断是否是刚从新数据快获取数据,如果是进行数据的交接

            /// 4,while (!ar.IsCompleted),等待子线程getBytesSyn调度完毕,当子线程没有完成之前,主线程可以在 该while语句块内进行任何后续操作,而且不用等待子线程的结束,在这个循环中编写代码是线程不安全的。

            /// 5,进行新旧数据的交接

            /// 6.sm.Close();关闭资源

            /// </summary>

            /// <param name="index"></param>

            /// <param name="sm"></param>

            public static void parsePcapSyn(int index, ShareMemory sm)

            {

                Func<ShareMemory, byte[]> fun = getBytesSyn;

                byte[] pktmdata = null;

                byte[] byteTemp = null;

                Global.openGLs[index].frameSum = 0;

                Global.openGLs[index].frameStartDictionary.Clear();

                //获取第一个数据块数据,长度

                uint mLength = sm.GetNextblock();

                pktmdata = new byte[mLength];

                sm.synRead(ref pktmdata, 0, pktmdata.Length);

                //上一块数据的长度,

                uint liftBlockLength = 0;

                //定义上一块读到的位置

                int liftBlockTemp = 0;

                //为第一次进入子线程调度做准备

                sm.nextMLength = sm.GetNextblock();

                //相位角

                int l_unAngleNo = 0, preAngle = 0;

                int packLength = 0;

                int temp = 24;

                int fileStart = 24;

                long leftLength = sm.get_m_FileSize() - fileStart;

                //文件开始读取的位置

                Global.openGLs[index].frameSum += 1;

                Global.openGLs[index].frameStartDictionary.Add(Global.openGLs[index].frameSum, fileStart);

                while (leftLength > 0)

                {

                    IAsyncResult ar = fun.BeginInvoke(sm, null, null);//主线程调用子线程开始执行TakeAWhile方法,并给它传递了参数

                    SharpGLForm.Instance.showPrograss(index, (int)((1.0 - (double)leftLength / sm.get_m_FileSize()) * 100));

                    //如果剩下的数据不足一包数据执行以下部分

                    //这里判断是否是刚从新数据快获取数据,如果是进行数据的交接

                    while (temp < 0)

                    {

                        //如果第一次进入此部分

                        packLength = (temp + 9 >= 0 ? pktmdata[temp + 9] : byteTemp[liftBlockTemp + 9]) * 256 + (temp + 8 >= 0 ? pktmdata[temp + 8] : byteTemp[liftBlockTemp + 8]);

                        fileStart += 16;

                        leftLength -= 16;

                        liftBlockTemp += 16;

                        temp += 16;

                        if (packLength != 1392)

                        {

                            liftBlockTemp += packLength;

                            temp += packLength;

                            fileStart += packLength;

                            leftLength -= packLength;

                            continue;

                        }

                        if ((temp + 42 >= 0 ? pktmdata[temp + 42] : byteTemp[liftBlockTemp + 42]) == 0xff && (temp + 43 >= 0 ? pktmdata[temp + 43] : byteTemp[liftBlockTemp + 43]) == 0xee)

                        {

                            preAngle = l_unAngleNo;

                            l_unAngleNo = ((temp + +42 + 132 + 3 >= 0 ? pktmdata[temp + 42 + 132 + 3] : byteTemp[liftBlockTemp + 42 + 132 + 3]) * 256 + (temp + 42 + 132 + 2 >= 0 ? pktmdata[temp + 42 + 132 + 2] : byteTemp[liftBlockTemp + 42 + 132 + 2])) / 10;

                            if (l_unAngleNo == 3600) l_unAngleNo = 0;

                            if (l_unAngleNo < preAngle)

                            {

                                l_unAngleNo = 0;

                                Global.openGLs[index].frameSum++;

                                Global.openGLs[index].frameStartDictionary.Add(Global.openGLs[index].frameSum, fileStart + 1392);

                            }

                        }

                        temp += 1392;

                        fileStart += 1392;

                        leftLength -= 1392;

                    }

                    while (temp + 1408 < mLength && mLength != 0)

                    {

                            packLength = pktmdata[temp + 9] * 256 + pktmdata[temp + 8];

                            fileStart += 16;

                            leftLength -= 16;

                            temp += 16;

                            //如果不等于1392则跳过这包数据

                            if (packLength != 1392)

                            {

                                temp += packLength;

                                fileStart += packLength;

                                leftLength -= packLength;

                                continue;

                            }

                            if (pktmdata[temp + 42] == 0xff && pktmdata[temp + 43] == 0xee)

                            {

                                preAngle = l_unAngleNo;

                                l_unAngleNo = (pktmdata[temp + 42 + 132 + 3] * 256 + pktmdata[temp + 42 + 132 + 2]) / 10;

                                if (l_unAngleNo == 3600) l_unAngleNo = 0;

                                if (l_unAngleNo < preAngle)

                                {

                                    l_unAngleNo = 0;

                                    Global.openGLs[index].frameSum++;

                                    Global.openGLs[index].frameStartDictionary.Add(Global.openGLs[index].frameSum, fileStart + 1392);

                                }

                            }

                            temp += 1392;

                            fileStart += 1392;

                            leftLength -= 1392;

                    }

                    while (!ar.IsCompleted)

                    {

                        //等待子线程调度完毕

                        //当子线程没有完成之前,主线程可以在 该while语句块内进行任何后续操作,而且不用等待子线程的结束

                    }

                    //获取新的数据块,整合旧数据块

                    byteTemp = pktmdata;

                    liftBlockTemp = temp;

                    liftBlockLength = mLength;

                    pktmdata = fun.EndInvoke(ar);//6秒之后我需要子线程的结果了,ok,从子线程中拿到结果

                    if (pktmdata == null) break;

                    mLength =(uint) pktmdata.Length;

                    temp = liftBlockTemp - (int)liftBlockLength;

                }

                sm.Close();

            }

            /// <summary>

            /// 异步多核三个线程读取paca文件信息的中间函数,主要功能是获取byte数组

            /// </summary>

            /// <param name="sm"></param>

            /// <returns></returns>

            static byte[] getBytesSyn(ShareMemory sm)

            {

              //  Log.printLog("进入TakeAWhile,句柄为:" + sm.get_m_pwData());

                //如果没有这一包

                if (sm.nextMLength == 0) return null;

                Func<ShareMemory, uint> fun = getIntPtrSyn;

                byte[] pktmdata = null;

                IAsyncResult ar = fun.BeginInvoke(sm, null, null);//主线程调用子线程开始执行TakeAWhile方法,并给它传递了参数

                pktmdata = new byte[sm.nextMLength];

                sm.synRead(ref pktmdata, 0, pktmdata.Length);

                while (!ar.IsCompleted)

                {

                    //当子线程没有完成之前,主线程可以在该while语句块内进行任何后续操作,而且不用等待子线程的结束

                //  Log.printLog("TakeAWhile,等待Take结束,句柄为:" + sm.get_m_pwData());

                }

                sm.nextMLength = fun.EndInvoke(ar);//6秒之后我需要子线程的结果了,ok,从子线程中拿到结果

                sm.do_syn_m_pwData();

                return pktmdata;

            }

            /// <summary>

            /// 异步多核三个线程读取paca文件信息的第三层函数,主要功能是获取byte数组的长度和下一个数据映射的句柄

            /// </summary>

            /// <param name="sm"></param>

            /// <returns></returns>

            static uint getIntPtrSyn(ShareMemory sm)

            {

              // Log.printLog("进入Take,句柄为:" + sm.get_m_pwData());

                uint temp = sm.synGetNextblock();

              // Log.printLog("Take结束,句柄为:" + sm.get_m_pwData());

                return temp;

            }

            #endregion

    相关文章

      网友评论

          本文标题:C# 并发读写内存文件映射

          本文链接:https://www.haomeiwen.com/subject/ievfsctx.html