Introduction
Sharing memory is a powerful tool and it can now be done simply....
You have an application, we will call it application "A.exe", and you would like it to pass data to your application "B.exe". How would you do this?
- You could share a file, but this will be slow and if the data is used a lot, it would put excessive demand on your hard drive.
- You could share data across a local network link, but this just adds more overhead for your PC.
- You could share some memory, but how?
For example, application "A" is a complex user interface that logs users in, reads databases, and adds user form controls for controlling attached hardware.
Application "B" needs to run at the same time within the same PC on another thread/CPU core. It controls hardware in real
time via LAN or USB, yet needs data that would require application "A"’s users database results.
Sharing memory in real time is the best way. However this is not as easy as it sounds......
Background
The memory on a PC is fully managed by the Operating System, in this case Microsoft Windows 7. The Operating System has to balance all the different
running applications over several CPU cores for all of the running "threads". The application's "A" thread will have no knowledge of the application's "B" thread
or its memory use. So how can we set aside some memory to share some data?
In the bad old days of programming, you would have typed "Reserve Memory Address XXX", and in "Basic" would have typed keywords like
PEEK
or POKE
to place the data in. However, if all your applications did this, you soon would have run out of memory, which did happen!
Until .NET Framework 4, sharing memory was hard to do. But thanks to some new functions, it is really easy and your application don’t
have to know anything about threads or memory as the new function takes care of the memory, thread safety all for you.
This new shared memory function is handled just like files; you open them with a name, add data to them, and share them across different applications.
The data can be a few bytes to Gigabytes. However, I prefer to use a small "buffer file of shared memory". The task of my shared memory file is to pass variables
and data from my different applications.
Another example: You could have a shared memory file called "Commands" which is only a few bytes big, sent from application A. Application
B reads the commands and replies with its shared memory file called "Results" and puts them ready for application A. The combination is limitless and you can have any
number of running applications.
For further reading, please refer to http://msdn.microsoft.com/en-us/library/dd997372.aspx.
Code Description
The code Imports the System.IO.MemoryMappedFiles
namespace
which has all the classes you need for controlling memory mapped files, and waits for the buttons MakeFile
or ReadFile
mouse click events to fire.
To write some data to share in memory, you do the following....
Call MakeMemoryMappedFile()
.
First, you declare an object; I used "File
" as a memory mapped
file which you can "Open" with the number of bytes you need (e.g., 26), and name it, here I have used "MemoryFile
".
Dim File=MemoryMappedFile.CreateOrOpen("MemoryFile",26)
Notice I have used "CreateOrOpen
". This is useful if your application could find that another application has already opened it with the same name.
You could just use "Create
" for even more simplicity.
Next, I generate an "Array of 26 bytes" called "bytes
".
This is going to be my byte memory buffer, which can hold anything I wish to share across the applications.
In this case, I am just going to place a simple count into "Bytes" as 1,2,3,4... This is all done in the "For Next" loop.
Now we need to make our shared memory called "MemoryFile
" viewable to our other applications. This is done by using an object I called "writer"
and calling the method "CreatViewAccessor
". This now makes the memory file data "Viewable
". You can set the start and size that you wish
your viewing application to see, I used 0 the Start of "bytes Array
" and the "bytes Array" length (26).
Using writer = File.CreateViewAccessor(0, bytes.Length)
With the "MemoryFile
" open and Viewable all that is left to do is to write our byte array to the shared memory this is done with:
writer.WriteArray(Of Byte)(0, bytes, 0, bytes.Length)
To read the data in shared memory you need to do the following.....
Call ReadMemoryMappedFile()
.
My object "File
" here is used to "Open" an "Existing" shared
memory file which we opened in the above method, called "MemoryFile
".
Using file = MemoryMappedFile.OpenExisting("MemoryFile")
Here Try
and Catch
is important to help us, as the shared memory file may not exist, so I catch the exception and simply show a
message box that it does not exist. You could add your own handler here. Note: unlike standard file handling, this class does not support "If.exist
".
With the reader open, the class needs to know what you want to access and view. This is done with my object called "reader
" and using
the "CreateViewAccessor
" method with the start and number of bytes to access. But first I ready a buffer to hold the data bytes to be read, I’ve also called
it "bytes
", because I know how many bytes I am sending - I've hard coded this the same size (26).
Then load the buffer with:
reader.ReadArray(Of Byte)(0, bytes, 0, bytes.Length)
Finally, I display the bytes converted to a string in a text box. Your code could parse the bytes for commands or data for further action
or events. You should close the memory just like you would do with a file. In this example, I left it open so it can be called recursively for demonstration.
The code shown here is just one form; the same code is repeated in a different application I called form 2, with just the data in the write array changed to show that you can change it.
Using the Code
The demo VB.NET application is two projects in the same VS2010 solution. They consist of one form each.
We use the System.IO.MemoryMappedFiles
namespace in both and my example uses a few bytes from your system memory.
Application Form1
writes a few bytes when you click the Makefile button. E.g., values 1, 2, 3, 4.. etc. You can read them back on the same form textbox
with the ReadFile button, or more importantly from the other application Form2
Readfile button.
Application Form2
Makefile button puts some different data (adds 10) to the same shared memory file so that you can see how easy it is to read the different values.
Once you play with the demo, you should be able to adapt it for your own applications.....
Imports System
Imports System.IO
Imports System.IO.MemoryMappedFiles
Public Class Form1
Private Sub MakeMemoryMappedFile()
Dim File = MemoryMappedFile.CreateOrOpen("MemoryFile", 26)
Dim bytes = New Byte(25) {}
For i As Integer = 0 To bytes.Length - 1
bytes(i) = i + 1
Next
Using writer = File.CreateViewAccessor(0, bytes.Length)
writer.WriteArray(Of Byte)(0, bytes, 0, bytes.Length)
End Using
End Sub
Private Sub ReadMemoryMappedFile()
Try
Using file = MemoryMappedFile.OpenExisting("MemoryFile")
Using reader = file.CreateViewAccessor(0, 26)
Dim bytes = New Byte(25) {}
reader.ReadArray(Of Byte)(0, bytes, 0, bytes.Length)
TextBox1.Text = ""
For i As Integer = 0 To bytes.Length - 1
TextBox1.AppendText(CStr(bytes(i)) + " ")
Next
End Using
End Using
Catch noFile As FileNotFoundException
TextBox1.Text = "Memory-mapped file does not exist."
Catch Ex As Exception
End Try
End Sub
Private Sub Btn_Make_Click(sender As System.Object, e As System.EventArgs) _
Handles Btn_Make.Click
MakeMemoryMappedFile()
End Sub
Private Sub Btn_Read_Click(sender As System.Object, e As System.EventArgs) _
Handles Btn_Read.Click
ReadMemoryMappedFile()
End Sub
End Class
History
- First version: 18/08/2011.