溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C#.Net通信共享內(nèi)存映射文件是什么

發(fā)布時間:2022-04-29 14:12:33 來源:億速云 閱讀:179 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“C#.Net通信共享內(nèi)存映射文件是什么”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“C#.Net通信共享內(nèi)存映射文件是什么”吧!

節(jié)點(diǎn)通信存在兩種模型:共享內(nèi)存(Shared memory)和消息傳遞(Messages passing)。

內(nèi)存映射文件對于托管世界的開發(fā)人員來說似乎很陌生,但它確實(shí)已經(jīng)是很遠(yuǎn)古的技術(shù)了,而且在操作系統(tǒng)中地位相當(dāng)。實(shí)際上,任何想要共享數(shù)據(jù)的通信模型都會在幕后使用它。

內(nèi)存映射文件究竟是個什么?

內(nèi)存映射文件允許你保留一塊地址空間,然后將該物理存儲映射到這塊內(nèi)存空間中進(jìn)行操作。物理存儲是文件管理,而內(nèi)存映射文件是操作系統(tǒng)級內(nèi)存管理。

C#.Net通信共享內(nèi)存映射文件是什么

C#.Net通信共享內(nèi)存映射文件是什么

優(yōu)勢:

1.訪問磁盤文件上的數(shù)據(jù)不需執(zhí)行I/O操作和緩存操作(當(dāng)訪問文件數(shù)據(jù)時,作用尤其顯著);

2.讓運(yùn)行在同一臺機(jī)器上的多個進(jìn)程共享數(shù)據(jù)(單機(jī)多進(jìn)程間數(shù)據(jù)通信效率最高);

利用文件與內(nèi)存空間之間的映射,應(yīng)用程序(包括多個進(jìn)程)可以通過直接在內(nèi)存中進(jìn)行讀寫來修改文件。.NET Framework 4 用托管代碼按照本機(jī)Windows函數(shù)訪問內(nèi)存映射文件的方式來訪問內(nèi)存映射文件,管理 Win32 中的內(nèi)存映射文件。

有兩種類型的內(nèi)存映射文件:

  • 持久內(nèi)存映射文件

持久文件是與磁盤上的源文件關(guān)聯(lián)的內(nèi)存映射文件。在最后一個進(jìn)程使用完此文件后,數(shù)據(jù)將保存到磁盤上的源文件中。這些內(nèi)存映射文件適合用來處理非常大的源文件。

  • 非持久內(nèi)存映射文件

非持久文件是未與磁盤上的源文件關(guān)聯(lián)的內(nèi)存映射文件。當(dāng)最后一個進(jìn)程使用完此文件后,數(shù)據(jù)將丟失,并且垃圾回收功能將回收此文件。這些文件適用于為進(jìn)程間通信(IPC) 創(chuàng)建共享內(nèi)存。

1)在多個進(jìn)程之間進(jìn)行共享(進(jìn)程可通過使用由創(chuàng)建同一內(nèi)存映射文件的進(jìn)程所指派的公用名來映射到此文件)。

2)若要使用一個內(nèi)存映射文件,則必須創(chuàng)建該內(nèi)存映射文件的完整視圖或部分視圖。還可以創(chuàng)建內(nèi)存映射文件的同一部分的多個視圖,進(jìn)而創(chuàng)建并發(fā)內(nèi)存。為了使兩個視圖能夠并發(fā),必須基于同一內(nèi)存映射文件創(chuàng)建這兩個視圖。

3)如果文件大于應(yīng)用程序用于內(nèi)存映射的邏輯內(nèi)存空間(在 32 位計算機(jī)上為2GB),則還需要使用多個視圖。

有兩種類型的視圖:流訪問視圖和隨機(jī)訪問視圖。使用流訪問視圖可對文件進(jìn)行順序訪問;在使用持久文件時,隨機(jī)訪問視圖是首選方法。

.Net 共享內(nèi)存 內(nèi)存映射文件原理

通過操作系統(tǒng)的內(nèi)存管理器訪問的,因此會自動將此文件分隔為多個頁,并根據(jù)需要對其進(jìn)行訪問。您不需要自行處理內(nèi)存管理。如下圖:

C#.Net通信共享內(nèi)存映射文件是什么

C# .Net 共享內(nèi)存 演示代碼

   //持久內(nèi)存映射文件:基于現(xiàn)有文件創(chuàng)建一個具有指定公用名的內(nèi)存映射文件
    using (var mmf = MemoryMappedFile.CreateFromFile(@"c:\內(nèi)存映射文件.data", FileMode.Open, "公用名"))
    {
        //通過指定的 偏移量和大小 創(chuàng)建內(nèi)存映射文件視圖服務(wù)器
        using (var accessor = mmf.CreateViewAccessor(offset, length)) //偏移量,可以控制數(shù)據(jù)存儲的內(nèi)存位置;大小,用來控制存儲所占用的空間
        {
            //Marshal提供了一個方法集,這些方法用于分配非托管內(nèi)存、復(fù)制非托管內(nèi)存塊、將托管類型轉(zhuǎn)換為非托管類型,此外還提供了在與非托管代碼交互時使用的其他雜項(xiàng)方法。
            int size = Marshal.SizeOf(typeof(char));
            //修改內(nèi)存映射文件視圖
            for (long i = 0; i < length; i += size)
            {
                char c= accessor.ReadChar(i);
                accessor.Write(i, ref c);
            }
        }
    }
    //另一個進(jìn)程或線程可以,在系統(tǒng)內(nèi)存中打開一個具有指定名稱的現(xiàn)有內(nèi)存映射文件
    using (var mmf = MemoryMappedFile.OpenExisting("公用名"))
    {
        using (var accessor = mmf.CreateViewAccessor(4000000, 2000000))
        {
            int size = Marshal.SizeOf(typeof(char));
            for (long i = 0; i < length; i += size)
            {
                char c = accessor.ReadChar(i);
                accessor.Write(i, ref c);
            }
        }
    }
//非持久內(nèi)存映射文件:未映射到磁盤上的現(xiàn)有文件的內(nèi)存映射文件
    using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("testmap", 10000))
    {
        bool mutexCreated;
        //進(jìn)程間同步
        Mutex mutex = newMutex(true, "testmapmutex", out mutexCreated);
        using (var stream = mmf.CreateViewStream()) //創(chuàng)建文件內(nèi)存視圖流 基于流的操作
        {
            var writer = newBinaryWriter(stream);
            writer.Write(1);
        }
        mutex.ReleaseMutex();
        Console.WriteLine("Start Process B and press ENTER to continue.");
        Console.ReadLine();
        mutex.WaitOne();
        using (MemoryMappedViewStream stream = mmf.CreateViewStream())
        {
            var reader = newBinaryReader(stream);
            Console.WriteLine("Process A says: {0}", reader.ReadBoolean());
            Console.WriteLine("Process B says: {0}", reader.ReadBoolean());
        }
        mutex.ReleaseMutex();
    }
    using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("testmap"))
    {
         Mutex mutex = Mutex.OpenExisting("testmapmutex");
        mutex.WaitOne();
       using (var stream = mmf.CreateViewStream(1, 0))//注意這里的偏移量
        {
            var writer = newBinaryWriter(stream);
            writer.Write(0);
        }
        mutex.ReleaseMutex();
    }

C# .Net 進(jìn)程間通信共享內(nèi)存

完整示例:C#共享內(nèi)存非持久化方式通訊的例子,通訊時的線程和進(jìn)程控制也沒有問題。

  • 先啟動消息服務(wù)IMServer_Message,

  • 再啟動狀態(tài)服務(wù)IMServer_State,

  • IMServer_Message回車一次(創(chuàng)建共享內(nèi)存公用名和公用線程鎖,并視圖流方式寫共享內(nèi)存),

  • IMServer_State回車一次(獲取共享內(nèi)存并視圖流方式寫、視圖訪問器寫入結(jié)構(gòu)體類型)

  • 并立刻IMServer_Message再回車一次(讀取剛剛寫入的信息),

  • 觀察IMServer_State屏顯變化并等待(線程鎖)約5s(線程鎖被釋放)后

  • 在IMServer_Message上觀察屏顯(顯示剛剛寫入共享內(nèi)存的信息)

IMServer_Message.exe 代碼

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using System.Threading;
namespace IMServer_Message
{
    /// <summary>
    /// 用于共享內(nèi)存方式通信的 值類型 結(jié)構(gòu)體
    /// </summary>
    public struct ServiceMsg
    {
        public int Id;
        public long NowTime;
    }
    internal class Program
    {
        private static void Main(string[] args)
        {
            Console.Write("請輸入共享內(nèi)存公用名(默認(rèn):testmap):");
            string shareName = Console.ReadLine();
            if (string.IsNullOrEmpty(shareName))
                shareName = "testmap";
            using (MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen(shareName, 1024000,MemoryMappedFileAccess.ReadWrite))
            {
                bool mutexCreated;
                //進(jìn)程間同步
                var mutex = new Mutex(true, "testmapmutex", out mutexCreated);
                using (MemoryMappedViewStream stream = mmf.CreateViewStream()) //創(chuàng)建文件內(nèi)存視圖流
                {
                    var writer = new BinaryWriter(stream);
                    for (int i = 0; i < 5; i++)
                    {
                        writer.Write(i);
                        Console.WriteLine("{0}位置寫入流:{0}", i);
                    }
                }
                mutex.ReleaseMutex();
                Console.WriteLine("啟動狀態(tài)服務(wù),按【回車】讀取共享內(nèi)存數(shù)據(jù)");
                Console.ReadLine();
                mutex.WaitOne();
                using (MemoryMappedViewStream stream = mmf.CreateViewStream())
                {
                    var reader = new BinaryReader(stream);
                    for (int i = 0; i < 10; i++)
                    {
                        Console.WriteLine("{1}位置:{0}", reader.ReadInt32(), i);
                    }
                }
                using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor(1024, 10240))
                {
                    int colorSize = Marshal.SizeOf(typeof (ServiceMsg));
                    ServiceMsg color;
                    for (int i = 0; i < 50; i += colorSize)
                    {
                        accessor.Read(i, out color);
                        Console.WriteLine("{1}\tNowTime:{0}", new DateTime(color.NowTime), color.Id);
                    }
                }
                mutex.ReleaseMutex();
            }
            Console.WriteLine("測試: 我是 即時通訊 - 消息服務(wù) 我啟動啦?。?!");
            Console.ReadKey();
        }
    }
}

IMServer_State.exe代碼

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using System.Threading;
namespace IMServer_State
{
    /// <summary>
    /// 用于共享內(nèi)存方式通信的 值類型 結(jié)構(gòu)體
    /// </summary>
    public struct ServiceMsg
    {
        public int Id;
        public long NowTime;
    }
    internal class Program
    {
        private static void Main(string[] args)
        {
            Console.Write("請輸入共享內(nèi)存公用名(默認(rèn):testmap):");
            string shareName = Console.ReadLine();
            if (string.IsNullOrEmpty(shareName))
                shareName = "testmap";
            using (MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen(shareName, 1024000,MemoryMappedFileAccess.ReadWrite))
            {
                Mutex mutex = Mutex.OpenExisting("testmapmutex");
                mutex.WaitOne();
                using (MemoryMappedViewStream stream = mmf.CreateViewStream(20, 0)) //注意這里的偏移量
                {
                    var writer = new BinaryWriter(stream);
                    for (int i = 5; i < 10; i++)
                    {
                        writer.Write(i);
                        Console.WriteLine("{0}位置寫入流:{0}", i);
                    }
                }
                using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor(1024, 10240))
                {
                    int colorSize = Marshal.SizeOf(typeof (ServiceMsg));
                    var color = new ServiceMsg();
                    for (int i = 0; i < colorSize*5; i += colorSize)
                    {
                        color.Id = i;
                        color.NowTime = DateTime.Now.Ticks;
                        //accessor.Read(i, out color);
                        accessor.Write(i, ref color);
                        Console.WriteLine("{1}\tNowTime:{0}", new DateTime(color.NowTime), color.Id);
                        Thread.Sleep(1000);
                    }
                }
                Thread.Sleep(5000);
                mutex.ReleaseMutex();
            }
            Console.WriteLine("測試: 我是 即時通訊 - 狀態(tài)服務(wù) 我啟動啦?。?!");
            Console.ReadKey();
        }
    }
}

感謝各位的閱讀,以上就是“C#.Net通信共享內(nèi)存映射文件是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對C#.Net通信共享內(nèi)存映射文件是什么這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI