November 26, 2014
Hot Topics:

Using Memory-Mapped Files in .NET 4.0

  • July 14, 2009
  • By Jani Järvinen
  • Send Email »
  • More Articles »

Sharing Memory Between Objects and Processes

Previously, you saw how you can use memory-mapped files to ease access to a file's contents using simple memory operations. The next step is to learn how to use this knowledge to share memory inside your application and also between processes.

When mapping a file's contents into memory, you need to specify, among other things, which file on disk you want and which portion of it you are mapping. This is easy, but what's not as obvious is that you can map the same file multiple times, even if the mapped regions are the same or they overlap (Figure 2).


Figure 2. Portions of a file can be mapped multiple times.

By utilizing this knowledge, it is possible to let multiple threads to access the contents of the file, without having to worry about concurrency or locking. It is simply enough to know how to read and write from the memory block. And with the view accessor class, you already know how to do that. Here is an example of how you can map the beginning of a file into more than one accessor object. Naturally, the file name of the file must match each time you create a new view accessor. This is easy to accomplish if you use the same memory mapping object twice:

  ...
  MemoryMappedViewAccessor accessor1 =
    mmf.CreateViewAccessor();
  MemoryMappedViewAccessor accessor2 =
    mmf.CreateViewAccessor();
      
  // write
  byte writeChr = Encoding.ASCII.GetBytes("Z")[0];
  accessor1.Write(0, writeChr);
  
  // read
  byte readChr = accessor2.ReadByte(0);
  string status = (readChr == writeChr) ? "Match!" : "No match!";
  MessageBox.Show(status); // match

Note that once the writing to the view's memory block has completed, the contents of the file has changed. The operating system might not immediately flush the changed data to disk, but usually this is near-instant. No separate commit or flush operation is needed; this is one of the beauties of memory-mapped files.

To share the mapped file between processes, you must give your view a name. The name allows you to open a synchronized view in more than one process, and it goes without saying that the name must be unique among object names in the system. Assume that you want to send a string from one process into another. Here is the code to open a named memory-mapped view, and to write a simple string to the view:

  MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen(
    "my-mmf-map-name", 1000);
  MemoryMappedViewAccessor accessor =
    mmf.CreateViewAccessor();
  string message = "Hello, Memory-Mapped World!";
  byte[] asciiBytes = Encoding.ASCII.GetBytes(message);
  accessor.WriteArray(0, asciiBytes, 0, asciiBytes.Length);
  MessageBox.Show("Message written.");

Note how in the above code there is no physical file to contain the data. Because of this, you need to specify a capacity parameter when calling the CreateOrOpen method. In the above code, this is set to 1,000 bytes. The capacity defines the size of the memory block. But more on this shortly. Returning to the example of sharing information between processes, the next step would be to use the similarly-named view in another process to read the string back:

  MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen(
    "my-mmf-map-name", 1000);
  MemoryMappedViewAccessor accessor =
    mmf.CreateViewAccessor();
  byte byteValue;
  int index = 0;
  StringBuilder message = new StringBuilder();
  do
  {
    byteValue = accessor.ReadByte(index);
    if (byteValue != 0)
    {
      char asciiChar = (char)byteValue;
      message.Append(asciiChar);
    }
    index++;
  } while (byteValue != 0);
  MessageBox.Show("Found text: \""+message+"\".");

In the above code, the second process opens the same memory-mapped view by using the CreateOrOpen static method of the MemoryMappedFile class. Then, the accessor object is created just the same as before, and the data is read byte-by-byte until a zero terminator byte is found. Then, the message is processed, which in this case means showing it on the screen. A very easy way to do inter-process communication (IPC) between processes!





Page 3 of 4



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel