C# 进程间共享内存通信方式

从别处看到一篇文章做进程间通信很好使,唯一的问题是,需要注意using的用法,Using有个用法3,

using 语句允许程序员指定使用资源的对象应当何时释放资源。using 语句中使用的对象必须实现 IDisposable 接口。此接口提供了 Dispose 方法,该方法将释放此对象的资源。

①可以在 using 语句之中声明对象。
      Font font2 = new Font("Arial", 10.0f);
      using (font2)
      {
          // use font2
      }
    ②可以在 using 语句之前声明对象。
      using (Font font2 = new Font("Arial", 10.0f))
      {
          // use font2
      }
    ③可以有多个对象与 using 语句一起使用,但是必须在 using 语句内部声明这些对象。
        using (Font font3=new Font("Arial",10.0f), font4=new Font("Arial",10.0f))
      {
          // Use font3 and font4.
      }

使用规则
    ①using只能用于实现了IDisposable接口的类型,禁止为不支持IDisposable接口的类型使用using语句,否则会出现编译错误;
  ②using语句适用于清理单个非托管资源的情况,而多个非托管对象的清理最好以try-finnaly来实现,因为嵌套的using语句可能存在隐藏的Bug。内层using块引发异常时,将不能释放外层using块的对象资源;
  ③using语句支持初始化多个变量,但前提是这些变量的类型必须相同,例如:
        using(Pen p1 = new Pen(Brushes.Black), p2 = new Pen(Brushes.Blue))
      {
          //
      }
    ④针对初始化对个不同类型的变量时,可以都声明为IDisposable类型,例如:
        using (IDisposable font = new Font("Verdana", 12), pen = new Pen(Brushes.Black))
      {
          float size = (font as Font).Size;
          Brush brush = (pen as Pen).Brush;
      }

using实质
    在程序编译阶段,编译器会自动将using语句生成为try-finally语句,并在finally块中调用对象的Dispose方法,来清理资源。所以,using语句等效于try-finally语句,例如:
    Font f2 = new Font("Arial", 10, FontStyle.Bold);
  try
  {
      //执行文本绘制操作
  }
  finally
  {
      if (f2 != null) ((IDisposable)f2).Dispose();
  }

好了下面开始粘贴从别处看来的

C# .Net 多进程同步通信共享内存内存映射文件 Memory Mapped

[摘要:节面通讯存正在两种模子:同享内存(Shared memory)战音讯传送(Messages passing)。 内存映照文件对托管天下的开辟职员来讲好像很目生,但它确切已是很太古的技巧了,并且正在操纵系节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing)。

内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作系统中地位相当。实际上,任何想要共享数据的通信模型都会在幕后使用它。

内存映射文件究竟是个什么?内存映射文件允许你保留一块地址空间,然后将该物理存储映射到这块内存空间中进行操作。物理存储是文件管理,而内存映射文件是操作系统级内存管理

优势
     1.访问磁盘文件上的数据不需执行I/O操作和缓存操作(当访问文件数据时,作用尤其显著);
     2.让运行在同一台机器上的多个进程共享数据(单机多进程间数据通信效率最高);

利用文件与内存空间之间的映射,应用程序(包括多个进程)可以通过直接在内存中进行读写来修改文件。.NET Framework 4 用托管代码按照本机Windows函数访问内存映射文件的方式来访问内存映射文件,管理 Win32 中的内存映射文件 。

有两种类型的内存映射文件:

  • 持久内存映射文件

持久文件是与磁盘上的源文件关联的内存映射文件。在最后一个进程使用完此文件后,数据将保存到磁盘上的源文件中。这些内存映射文件适合用来处理非常大的源文件。

  • 非持久内存映射文件

非持久文件是未与磁盘上的源文件关联的内存映射文件。当最后一个进程使用完此文件后,数据将丢失,并且垃圾回收功能将回收此文件。这些文件适用于为进程间通信 (IPC)
创建共享内存。

1)在多个进程之间进行共享(进程可通过使用由创建同一内存映射文件的进程所指派的公用名来映射到此文件)。

2)若要使用一个内存映射文件,则必须创建该内存映射文件的完整视图或部分视图。还可以创建内存映射文件的同一部分的多个视图,进而创建并发内存为了使两个视图能够并发,必须基于同一内存映射文件创建这两个视图

3)如果文件大于应用程序用于内存映射的逻辑内存空间(在 32
位计算机上为2GB),则还需要使用多个视图。

有两种类型的视图:流访问视图和随机访问视图。使用流访问视图可对文件进行顺序访问;在使用持久文件时,随机访问视图是首选方法。

.Net 共享内存内存映射文件原理:通过操作系统的内存管理器访问的,因此会自动将此文件分隔为多个页,并根据需要对其进行访问。您不需要自行处理内存管理。如下图:

C#
.Net
共享内存演示代码如下:

//持久内存映射文件:基于现有文件创建一个具有指定公用名的内存映射文件

using (var mmf = MemoryMappedFile.CreateFromFile(@"c:内存映射文件.data",FileMode.Open, "公用名"))
    {
        //通过指定的 偏移量和大小 创建内存映射文件视图服务器
        using (var accessor
= mmf.CreateViewAccessor(offset, length)) //偏移量,可以控制数据存储的内存位置;大小,用来控制存储所占用的空间
        {
            //Marshal提供了一个方法集,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型,此外还提供了在与非托管代码交互时使用的其他杂项方法。

int size = Marshal.SizeOf(typeof(char));

//修改内存映射文件视图
            for (long i = 0; i < length; i += size)
            {
                char c= accessor.ReadChar(i);
                accessor.Write(i, ref c);
            }
        }
    }

//另一个进程或线程可以,在系统内存中打开一个具有指定名称的现有内存映射文件

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

//非持久内存映射文件:未映射到磁盘上的现有文件的内存映射文件

using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("testmap", 10000))
    {
        bool mutexCreated;
        //进程间同步
        Mutex mutex
= newMutex(true, "testmapmutex", out mutexCreated);
        using (var stream
= mmf.CreateViewStream()) //创建文件内存视图流 基于流的操作
        {
            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 
进程间通信 共享内存 完整示例: C#共享内存非持久化方式通讯的例子,通讯时的线程和进程控制也没有问题。如下是实现的代码。

先启动消息服务IMServer_Message,

再启动状态服务IMServer_State,

IMServer_Message回车一次(创建共享内存公用名和公用线程锁,并视图流方式写共享内存),

IMServer_State回车一次(获取共享内存并视图流方式写、视图访问器写入结构体类型)

并立刻IMServer_Message再回车一次(读取刚刚写入的信息),

观察IMServer_State屏显变化并等待(线程锁)约5s(线程锁被释放)后

在IMServer_Message上观察屏显(显示刚刚写入共享内存的信息)

 IMServer_Message.exe
代码

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using System.Threading;

namespace IMServer_Message
{
    /// <summary>
    /// 用于共享内存方式通信的 值类型 结构体
    /// </summary>
    public struct ServiceMsg
    {
        public int Id;
        public long NowTime;
    }

internal class Program
    {
        private static void Main(string[]
args)
        {
           
Console.Write("请输入共享内存公用名(默认:testmap):");
            string
shareName = Console.ReadLine();
            if
(string.IsNullOrEmpty(shareName))
               
shareName = "testmap";
            using
(MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen(shareName,
1024000,MemoryMappedFileAccess.ReadWrite))
            {
               
bool mutexCreated;
               
//进程间同步
               
var mutex = new Mutex(true, "testmapmutex", out mutexCreated);
               
using (MemoryMappedViewStream stream = mmf.CreateViewStream()) //创建文件内存视图流
               
{
                   
var writer = new BinaryWriter(stream);
                   
for (int i = 0; i < 5; i++)
                   
{
                       
writer.Write(i);
                       
Console.WriteLine("{0}位置写入流:{0}", i);
                   
}
               
}

mutex.ReleaseMutex();

Console.WriteLine("启动状态服务,按【回车】读取共享内存数据");
               
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("测试: 我是 即时通讯 - 消息服务 我启动啦!!!");
           
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>
    /// 用于共享内存方式通信的 值类型 结构体
    /// </summary>
    public struct ServiceMsg
    {
        public int Id;
        public long NowTime;
    }

internal class Program
    {
        private static void Main(string[]
args)
        {
            Console.Write("请输入共享内存公用名(默认: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("测试: 我是 即时通讯 - 状态服务 我启动啦!!!");
           
Console.ReadKey();
        }
    }
}

时间: 2024-11-05 21:33:48

C# 进程间共享内存通信方式的相关文章

Windows进程间共享内存通信实例

抄抄补补整出来 采用内存映射文件实现WIN32进程间的通讯:Windows中的内存映射文件的机制为我们高效地操作文件提供了一种途径,它允许我们在WIN32进程中保留一段内存区域,把硬盘或页文件上的目标文件映射到这段虚拟内存中.注意:在程序实现中必须考虑各进程之间的同步问题. 在Windows操作系统下,任何一个进程不允许读取.写入或是修改另一个进程的数据(包括变量.对象和内存分配等),但是在某个进程内创建的文件映射对象的视图却能够为多个其他进程所映射,这些进程共享的是物理存储器的同一个页面. 因

Linux 进程间共享内存 SYSTEMV

#include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, int size, int shmflag) key取值为IPC_PRIVATE时,shmflag应为IPC_CREAT,则新建共享内存key取值不为IPC_PRIVATE则应为已创建的key值,shmflag不应包含IPC_CREAT和IPC_EXCL,且大小小于等于原共享内存大小成功则返回共享内存id,失败返回-1 void *shmat(int sh

linux 进程间共享内存示例

写入端: #include <iostream> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <sys/shm.h> using namespace std; struct MappingDataType { int mappingData; }; bool SetUsedPID(string mappingName) { void *shm = NULL

利用内存映射文件在两个进程间共享数据 转

private hMapFile: THandle; MapFilePointer: Pointer; public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin hMapFile := CreateFileMapping ( $FFFFFFFF, // 特殊内存映射句柄 nil, page_

Android系统匿名共享内存Ashmem(Anonymous Shared Memory)在进程间共享的原理分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6666491 在前面一篇文章Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析中,我们系统地介绍了Android系统匿名共享内存的实现原理,其中着重介绍了它是如何辅助内存管理系统来有效地管理内存的,在再前面一篇文章Android系统匿名共享内存Ashmem(Anonymous Share

windows核心编程之进程间共享数据

有时候我们会遇到window进程间共享数据的需求,例如说我想知道系统当前有多少某个进程的实例. 我们能够在程序中定义一个全局变量.初始化为0.每当程序启动后就加1.当然我们我们能够借助第三方介质来储存这个变量,然后解析. 这样做必须做到先写入后解析.不能实时更新数据.假设不考虑其它储存介质.仅仅是进程中的通信,应该怎么做呢?windows提供了一些可行的方法,以下介绍经常使用的两种. 一.共享数据段 #include "stdafx.h" #include <Windows.h&

进程-IPC 共享内存和消息队列 (三)

详见:https://github.com/ZhangzheBJUT/linux/blob/master/IPC(%E4%B8%89).md 五 共享内存 5.1. 共享内存简介 共享内存指多个进程共享同一块物理内存,它只能用于同一台机器上的两个进程之间的通信.在进程的逻辑地址空间中有一段地址范围是用来进行内存映射使用的,该段逻辑地址空间可以映射到共享的物理内存地址上(进程空间介绍:http://blog.csdn.net/zhangzhebjut/article/details/3906025

android进程间共享简单数据

我们知道,在android中,保存简单的数据最方便的就是使用SharedPreferences,然而,SharedPreferences虽然说也可以设置成进程间共享数据,但是并不可靠(更致命的是,不同级别的应用是无法使用SharedPreferences进行共享的,比如,普通应用无法读取系统应用的SharedPreferences数据). 那如何才能进行简单数据的跨进程共享呢,Settings.System可以很方便的进行跨进程共享数据,使用凡是也很简单: //往系统配置表里添加自定义数据 Se

python 进程间共享数据 (二)

Python中进程间共享数据,除了基本的queue,pipe和value+array外,还提供了更高层次的封装.使用multiprocessing.Manager可以简单地使用这些高级接口. Manager()返回的manager对象控制了一个server进程,此进程包含的python对象可以被其他的进程通过proxies来访问.从而达到多进程间数据通信且安全. Manager支持的类型有list,dict,Namespace,Lock,RLock,Semaphore,BoundedSemaph