共有メモリ (メモリ マップト ファイル) を利用する

C#で共有メモリ (メモリ マップト ファイル) を利用するコードを紹介します。

概要

C#で共有メモリを使う場合には、メモリ マップト ファイル (Memory Mapped File) と呼ばれる機能を利用します。この記事では共有メモリを利用してプログラム間でデータの値を共有するコードを紹介します。

他の方法

別々のプログラムで値の受け渡しをする方法として、DDE通信を利用する方法もあります。DDE通信は以前のバージョンのWindowsではよく利用されていた機能ですが、現在では共有メモリなどの機能があるため、あまり利用されない機能です。DDEについてはこちらの記事を参照してください。

プログラム例

UI:書き込み側

下図のUIを作成します、フォームにボタンと複数行のテキストボックスを配置します。

コード:書き込み側

下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.MemoryMappedFiles;

namespace SimpleMmapWriter
{
  public partial class FormMain : Form
  {
    public FormMain()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      MemoryMappedFile mmf = MemoryMappedFile.CreateNew("SharedMemoryTest", 256);
      MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor();

      string value = "ペンギンが滑った";
      char[] data = value.ToCharArray();
      accessor.WriteArray<char>(0,data,0,data.Length);
      accessor.Dispose();

      textBox1.Text += "共有メモリマップ ファイルに書き込みました。";
    }
  }
}

解説

フォームのボタンをクリックすると以下の処理が実行されます。

MemoryMappedFile オブジェクトを作成します。オブジェクトの作成はnew キーワードではなく、CreateNew() メソッドを呼び出します。第一引数にメモリマップトファイルの名称を与えます。第二引数はデータを格納できる長さを与えます。
オブジェクトの作成後、MemoryMappedFile オブジェクトにアクセスするっためのアクセッサを作成します。アクセッサはMemoryMappedViewAccessor オブジェクトを用意します。アクセッサは、MemoryMappedFile オブジェクトのCreateViewAccessor()メソッドを呼び出して取得します。
  MemoryMappedFile mmf = MemoryMappedFile.CreateNew("SharedMemoryTest", 256);
  MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor();

データをメモリマップとファイルに書き込みます。書き込みは MemoryMappedViewAccessor オブジェクトのWriteメソッドまたは、WriteArray メソッドを利用します。今回はchar[]配列の文字列を書き込むため、WriteArrayメソッドを利用してデータを書き込んでいます。
  string value = "ペンギンが滑った";
  char[] data = value.ToCharArray();
  accessor.WriteArray<char>(0,data,0,data.Length);

処理の完了後、MemoryMappedViewAccessor オブジェクトのDispiose() メソッドを呼び出し、アクセッサを開放します。
  accessor.Dispose();
補足
書き込み側で、MemoryMappedFile を開放するとファイルそのものがなくなってしまうため、プログラム終了までMemoryMappedFile オブジェクトは保持しておく必要があります。

  accessor.Dispose();
  mmf.Dispose(); //この行は不要

UI:読み込み側

下図のUIを作成します。フォームにボタンと複数行のテキストボックスを配置します。

コード:読み込み側

下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.MemoryMappedFiles;

namespace SimpleMmapReader
{
  public partial class FormMain : Form
  {
    public FormMain()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("SharedMemoryTest");
      MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor();

      char[] data = new char[256];
      int readsize = accessor.ReadArray<char>(0,data,0,256);

      textBox1.Text += new string(data);
            
      accessor.Dispose();
      mmf.Dispose();
    }
  }
}

解説

フォームのボタンをクリックすると以下の処理が実行されます。

MemoryMappedFile オブジェクトを作成します。読み取りでのMemoryMappedFile オブジェクトを作成する場合は、既に存在するメモリマップトファイルを参照するため、MemoryMappedFileクラスのOpenExisting()メソッドを呼び出します。引数には、メモリマップトファイルの名称を与えます。
オブジェクトの作成後、MemoryMappedFile オブジェクトにアクセスするっためのアクセッサを作成します。アクセッサはMemoryMappedViewAccessor オブジェクトを用意します。アクセッサは、MemoryMappedFile オブジェクトのCreateViewAccessor()メソッドを呼び出して取得します。
  MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("SharedMemoryTest");
  MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor();

メモリマップトファイルからデータを読み出します。読み出しは、Readメソッド、または ReadArrayメソッドを利用します。今回は文字列を読み出すためReadArray()メソッドを呼び出してchar[]配列を読み込みます。
読み込んだchar[]配列をstringの文字列型に変換してテキストボックスに表示します。
  char[] data = new char[256];
  int readsize = accessor.ReadArray<char>(0,data,0,256);

  textBox1.Text += new string(data);

処理が終わったらアクセッサのオブジェクトのDisposeメソッドを呼び出しアクセッサを開放します。また、メモリマップトファイルオブジェクトのDisposeメソッドを呼び出し、メモリマップトファイルを閉じます。
  accessor.Dispose();
  mmf.Dispose();

実行結果

書き込み側のプログラムを実行します。下図のウィンドウが表示されます。


[button1]をクリックします。共有メモリマップファイルに書き込まれた旨のメッセージが表示されます。


読み込み側のプログラムを実行します。下図のウィンドウが表示されます。


読み込み側プログラムのフォームの[button1]をクリックします。書き込み側のプログラムで共有メモリに書き込んだ文字列の値が読み込み側のプログラムで取得できていることが確認できます。


共有メモリである、メモリ マップト ファイルを利用して、プログラム間でデータの受け渡しができました。

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
作成日: 2018-12-19
Copyright © iPentec all rights reserverd.